add chart to PDF command engine, add svg salamander parser

This commit is contained in:
Jörg Prante 2021-12-16 10:41:32 +01:00
parent 08686de066
commit 683ab49c83
126 changed files with 42955 additions and 21 deletions

View file

@ -11,10 +11,6 @@ import java.util.List;
*/
public final class QuickChart {
private final static int WIDTH = 600;
private final static int HEIGHT = 400;
private QuickChart() {
}
@ -23,12 +19,14 @@ public final class QuickChart {
String yTitle,
String seriesName,
double[] xData,
double[] yData) {
double[] yData,
int width,
int height) {
double[][] yData2d = { yData };
if (seriesName == null) {
return getChart(chartTitle, xTitle, yTitle, null, xData, yData2d);
return getChart(chartTitle, xTitle, yTitle, null, xData, yData2d, width, height);
} else {
return getChart(chartTitle, xTitle, yTitle, new String[]{seriesName}, xData, yData2d);
return getChart(chartTitle, xTitle, yTitle, new String[]{seriesName}, xData, yData2d, width, height);
}
}
@ -37,8 +35,10 @@ public final class QuickChart {
String yTitle,
String[] seriesNames,
double[] xData,
double[][] yData) {
XYChart chart = new XYChart(WIDTH, HEIGHT);
double[][] yData,
int width,
int height) {
XYChart chart = new XYChart(width, height);
chart.setTitle(chartTitle);
chart.setXAxisTitle(xTitle);
chart.setYAxisTitle(yTitle);
@ -60,8 +60,10 @@ public final class QuickChart {
String yTitle,
String seriesName,
List<? extends Double> xData,
List<? extends Double> yData) {
XYChart chart = new XYChart(WIDTH, HEIGHT);
List<? extends Double> yData,
int width,
int height) {
XYChart chart = new XYChart(width, height);
chart.setTitle(chartTitle);
chart.setXAxisTitle(xTitle);
chart.setYAxisTitle(yTitle);

View file

@ -16,7 +16,7 @@ public class QuickChartTest {
double[] xData = new double[] { 0.0, 1.0, 2.0 };
double[] yData = new double[] { 2.0, 1.0, 0.0 };
XYChart chart = QuickChart.getChart("Sample Chart",
"X", "Y", "y(x)", xData, yData);
"X", "Y", "y(x)", xData, yData, 640, 480);
chart.write(Files.newOutputStream(Paths.get("build/quickchart1.pdf")),
VectorGraphicsFormat.PDF);
}

View file

@ -115,18 +115,16 @@ public class ChartElement implements Element, Drawable, Dividable, WidthRespecti
float x = upperLeft.getX();
float y = upperLeft.getY() - getHeight();
PdfBoxGraphics2D pdfBoxGraphics2D = new PdfBoxGraphics2D(pdDocument, getWidth(), getHeight());
Logger.getLogger("").info("x=" + x + " y=" + y);
Logger.getLogger("").info("xData=" + Arrays.toString(xData));
Logger.getLogger("").info("yData=" + Arrays.toString(xData));
XYChart chart = QuickChart.getChart("Sample Chart",
"X", "Y", "y(x)", xData, yData);
chart.paint(pdfBoxGraphics2D, 600, 480);
XYChart chart = QuickChart.getChart("Hello Jörg",
"X", "Y", "y(x)", xData, yData, (int) getWidth(), (int) getHeight());
chart.paint(pdfBoxGraphics2D, (int) getWidth(), (int) getHeight());
PDFormXObject xFormObject = pdfBoxGraphics2D.getXFormObject();
xFormObject.setMatrix(AffineTransform.getTranslateInstance(x, y));
//Matrix matrix = new Matrix();
//matrix.translate(x, y);
Matrix matrix = new Matrix();
matrix.translate(x, y);
matrix.scale(scaleX, scaleY);
contentStream.saveGraphicsState();
//contentStream.transform(matrix);
contentStream.transform(matrix);
contentStream.drawForm(xFormObject);
contentStream.restoreGraphicsState();
if (drawListener != null) {

View file

@ -104,6 +104,17 @@
]
}
]
},
{
"type": "chart",
"x": 0,
"y": 150,
"width": 600,
"height": 480,
"scalex": 0.66,
"scaley": 0.66,
"xdata": [ 0.0, 1.0, 3.0, 7.0 ],
"ydata": [ 3.5, 2.5, 1.25, 0.8 ]
}
]
}

View file

@ -0,0 +1,109 @@
/*
* 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 January 26, 2004, 1:56 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.net.URI;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class A extends Group
{
public static final String TAG_NAME = "a";
URI href;
String title;
/** Creates a new instance of Stop */
public A()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("xlink:href")))
{
href = sty.getURIValue(getXMLBase());
}
if (getPres(sty.setName("xlink:title")))
{
title = sty.getStringValue();
}
}
/**
* Updates all attributes in this diagram associated with a time event.
* Ie, all attributes with track information.
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
boolean changeState = super.updateTime(curTime);
// if (trackManager.getNumTracks() == 0) return false;
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("xlink:href")))
{
href = sty.getURIValue(getXMLBase());
}
if (getPres(sty.setName("xlink:title")))
{
title = sty.getStringValue();
}
return changeState;
}
}

View file

@ -0,0 +1,215 @@
package org.xbib.graphics.svg;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class BufferPainter
{
public static final boolean DEBUG_PAINT = false;
public static class Cache
{
private final BufferedImage img;
private final Rectangle bounds;
private final AffineTransform transform;
public Cache(BufferedImage img, Rectangle bounds, AffineTransform transform)
{
this.img = img;
this.bounds = bounds;
this.transform = transform;
}
boolean isCompatible(AffineTransform tx)
{
return tx.getScaleX() == transform.getScaleX()
&& tx.getScaleY() == transform.getScaleY()
&& tx.getShearX() == transform.getShearX()
&& tx.getShearY() == transform.getShearY();
}
Rectangle getBoundsForTransform(AffineTransform tx)
{
double dx = tx.getTranslateX() - transform.getTranslateX();
double dy = tx.getTranslateY() - transform.getTranslateY();
return new Rectangle((int) (bounds.x + dx), (int) (bounds.y + dy),
bounds.width, bounds.height);
}
}
public static void paintElement(Graphics2D g, RenderableElement element) throws SVGException
{
if (element.cachedMask != null
|| (element.filter != null && !element.filter.filterEffects.isEmpty()))
{
renderElement(g, element);
} else
{
element.doRender(g);
}
}
private static float getTransformScale(Point2D.Float origin, Point2D.Float testPoint,
AffineTransform transform)
{
transform.transform(testPoint, testPoint);
float dx = testPoint.x - origin.x;
float dy = testPoint.y - origin.y;
return (float) Math.sqrt(dx * dx + dy * dy);
}
private static void renderElement(Graphics2D g, RenderableElement element) throws SVGException
{
AffineTransform transform = g.getTransform();
Graphics2D gg = (Graphics2D) g.create();
Rectangle elementBounds = element.getBoundingBox().getBounds();
Rectangle transformedBounds = transform.createTransformedShape(elementBounds).getBounds();
Rectangle dstBounds = new Rectangle(transformedBounds);
ImageObserver observer = element.diagram.getCurrentRenderTarget();
Cache cache = element.getBufferCache();
BufferedImage elementImage;
if (cache == null || observer == null || !cache.isCompatible(transform))
{
elementImage = renderToBuffer(gg, element, transform, transformedBounds, dstBounds);
if (observer != null)
{
// Only do caching if we are painting to a component.
Cache cacheEntry = new Cache(elementImage, new Rectangle(dstBounds), transform);
element.setBufferImage(cacheEntry);
}
} else
{
elementImage = cache.img;
dstBounds.setBounds(cache.getBoundsForTransform(transform));
}
// Reset the transform. We already accounted for it in the buffer image.
gg.setTransform(new AffineTransform());
gg.drawImage(elementImage, dstBounds.x, dstBounds.y, observer);
if (DEBUG_PAINT)
{
gg.setColor(Color.GREEN);
gg.drawRect(dstBounds.x, dstBounds.y, dstBounds.width, dstBounds.height);
if (!dstBounds.equals(transformedBounds))
{
gg.setColor(Color.PINK);
gg.drawRect(transformedBounds.x, transformedBounds.y, transformedBounds.width, transformedBounds.height);
}
}
gg.dispose();
}
private static BufferedImage renderToBuffer(Graphics2D gg, RenderableElement element,
AffineTransform transform, Rectangle transformedBounds,
Rectangle dstBounds) throws SVGException
{
Point2D.Float origin = new Point2D.Float(0, 0);
transform.transform(origin, origin);
// As filter operations are commonly implemented using convolutions they need to be
// aware of any possible scaling to compensate for it in their kernel size.
Point2D.Float testPoint = new Point2D.Float(1, 0);
float xScale = getTransformScale(origin, testPoint, transform);
testPoint.setLocation(0, 1);
float yScale = getTransformScale(origin, testPoint, transform);
List<FilterEffects.FilterOp> filterOps = element.filter == null
? Collections.emptyList()
: element.filter.filterEffects.stream()
.flatMap(f -> f.getOperations(dstBounds, xScale, yScale).stream())
.filter(Objects::nonNull)
.collect(Collectors.toList());
for (FilterEffects.FilterOp filterOp : filterOps)
{
int right = Math.max(dstBounds.x + dstBounds.width,
filterOp.requiredImageBounds.x + filterOp.requiredImageBounds.width);
int bottom = Math.max(dstBounds.y + dstBounds.height,
filterOp.requiredImageBounds.y + filterOp.requiredImageBounds.height);
dstBounds.x = Math.min(dstBounds.x, filterOp.requiredImageBounds.x);
dstBounds.y = Math.min(dstBounds.y, filterOp.requiredImageBounds.y);
dstBounds.width = right - dstBounds.x;
dstBounds.height = bottom - dstBounds.y;
}
BufferedImage elementImage = BufferPainter.paintToBuffer(gg, transform, dstBounds, transformedBounds,
element, null, true);
for (FilterEffects.FilterOp filterOp : filterOps)
{
elementImage = filterOp.op.filter(elementImage, null);
}
if (element.cachedMask != null)
{
// Draw the mask image. Implicitly the mask is empty i.e. has a completely black background.
// We can't draw the mask directly to the elementImage using the mask composite as
// masks may change the mask value a location at any time during mask realization.
BufferedImage maskImage = BufferPainter.paintToBuffer(gg, transform, dstBounds, transformedBounds,
element.cachedMask, Color.BLACK, false);
Graphics2D elementGraphics = (Graphics2D) elementImage.getGraphics();
elementGraphics.setRenderingHints(gg.getRenderingHints());
elementGraphics.setComposite(element.cachedMask.createMaskComposite());
elementGraphics.drawImage(maskImage, 0, 0, element.diagram.getCurrentRenderTarget());
elementGraphics.dispose();
}
return elementImage;
}
public static BufferedImage paintToBuffer(Graphics2D g, AffineTransform transform,
Rectangle srcBounds, RenderableElement element,
Color bgColor) throws SVGException
{
return paintToBuffer(g, transform, srcBounds, srcBounds, element, bgColor, false);
}
/*
* The srcBounds parameter is expected to be pre-transformed by the given transform.
*/
public static BufferedImage paintToBuffer(Graphics2D g, AffineTransform transform,
Rectangle dstBounds, Rectangle srcBounds,
RenderableElement element,
Color bgColor, boolean preMultiplied) throws SVGException
{
int type = preMultiplied
? BufferedImage.TYPE_INT_ARGB_PRE
: BufferedImage.TYPE_INT_ARGB;
BufferedImage img = new BufferedImage(dstBounds.width, dstBounds.height, type);
Graphics2D imgGraphics = (Graphics2D) img.getGraphics();
if (g != null)
{
imgGraphics.setRenderingHints(g.getRenderingHints());
} else if (bgColor != null)
{
imgGraphics.setColor(bgColor);
imgGraphics.fillRect(0, 0, img.getWidth(), img.getHeight());
}
int xRelative = srcBounds.x - dstBounds.x;
int yRelative = srcBounds.y - dstBounds.y;
imgGraphics.translate(xRelative, yRelative);
imgGraphics.clipRect(0, 0, srcBounds.width, srcBounds.height);
// Because we blit the image at the transformed location we have to compensate for the
// element location.
imgGraphics.translate(-srcBounds.x, -srcBounds.y);
imgGraphics.transform(transform);
element.doRender(imgGraphics);
imgGraphics.dispose();
return img;
}
}

View file

@ -0,0 +1,171 @@
/*
* 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 January 26, 2004, 5:25 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Circle extends ShapeElement
{
public static final String TAG_NAME = "circle";
float cx = 0f;
float cy = 0f;
float r = 0f;
Ellipse2D.Float circle = new Ellipse2D.Float();
/**
* Creates a new instance of Rect
*/
public Circle()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("cx")))
{
cx = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("cy")))
{
cy = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("r")))
{
r = sty.getFloatValueWithUnits();
}
circle.setFrame(cx - r, cy - r, r * 2f, r * 2f);
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
beginLayer(g);
renderShape(g, circle);
finishLayer(g);
}
@Override
public Shape getShape()
{
return shapeToParent(circle);
}
@Override
public Rectangle2D getBoundingBox() throws SVGException
{
return boundsToParent(includeStrokeInBounds(circle.getBounds2D()));
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
boolean changeState = super.updateTime(curTime);
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getPres(sty.setName("cx")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != cx)
{
cx = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("cy")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != cy)
{
cy = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("r")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != r)
{
r = newVal;
shapeChange = true;
}
}
if (shapeChange)
{
build();
// circle.setFrame(cx - r, cy - r, r * 2f, r * 2f);
// return true;
}
return changeState || shapeChange;
}
}

View file

@ -0,0 +1,174 @@
/*
* 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 January 26, 2004, 1:56 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Shape;
import java.awt.geom.Area;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class ClipPath extends SVGElement
{
public static final String TAG_NAME = "clippath";
public static final int CP_USER_SPACE_ON_USE = 0;
public static final int CP_OBJECT_BOUNDING_BOX = 1;
int clipPathUnits = CP_USER_SPACE_ON_USE;
/**
* Creates a new instance of Stop
*/
public ClipPath()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Called after the start element but before the end element to indicate
* each child tag that has been processed
*/
@Override
public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
{
super.loaderAddChild(helper, child);
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
clipPathUnits = (getPres(sty.setName("clipPathUnits"))
&& sty.getStringValue().equals("objectBoundingBox"))
? CP_OBJECT_BOUNDING_BOX
: CP_USER_SPACE_ON_USE;
}
public int getClipPathUnits()
{
return clipPathUnits;
}
public Shape getClipPathShape()
{
if (children.isEmpty())
{
return null;
}
if (children.size() == 1)
{
return ((ShapeElement) children.get(0)).getShape();
}
Area clipArea = null;
for (SVGElement svgElement : children) {
ShapeElement se = (ShapeElement) svgElement;
if (clipArea == null)
{
Shape shape = se.getShape();
if (shape != null)
{
clipArea = new Area(se.getShape());
}
continue;
}
Shape shape = se.getShape();
if (shape != null)
{
clipArea.intersect(new Area(shape));
}
}
return clipArea;
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @param curTime Time at which to evaluate node
* @return - true if this node has changed state as a result of the time
* update
* @throws SVGException
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getPres(sty.setName("clipPathUnits")))
{
String newUnitsStrn = sty.getStringValue();
int newUnits = newUnitsStrn.equals("objectBoundingBox")
? CP_OBJECT_BOUNDING_BOX
: CP_USER_SPACE_ON_USE;
if (newUnits != clipPathUnits)
{
clipPathUnits = newUnits;
shapeChange = true;
}
}
if (shapeChange)
{
build();
}
for (int i = 0; i < children.size(); ++i)
{
SVGElement ele = (SVGElement) children.get(i);
ele.updateTime(curTime);
}
return shapeChange;
}
}

View file

@ -0,0 +1,97 @@
/*
* 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 January 26, 2004, 1:56 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleSheet;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Defs extends TransformableElement
{
public static final String TAG_NAME = "defs";
/**
* Creates a new instance of Stop
*/
public Defs()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Called after the start element but before the end element to indicate
* each child tag that has been processed
*/
@Override
public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
{
super.loaderAddChild(helper, child);
// members.add(child);
}
@Override
public boolean updateTime(double curTime) throws SVGException
{
boolean stateChange = false;
for (SVGElement ele : children) {
stateChange = stateChange || ele.updateTime(curTime);
}
return super.updateTime(curTime) || stateChange;
}
public StyleSheet getStyleSheet()
{
for (int i = 0; i < getNumChildren(); ++i)
{
SVGElement ele = getChild(i);
if (ele instanceof Style)
{
return ((Style)ele).getStyleSheet();
}
}
return null;
}
}

View file

@ -0,0 +1,82 @@
/*
* 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 September 19, 2004, 1:56 AM
*/
package org.xbib.graphics.svg;
/**
* Holds title textual information within tree
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Desc extends SVGElement
{
public static final String TAG_NAME = "desc";
StringBuffer text = new StringBuffer();
/**
* Creates a new instance of Stop
*/
public Desc()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Called during load process to add text scanned within a tag
*/
@Override
public void loaderAddText(SVGLoaderHelper helper, String text)
{
this.text.append(text);
}
public String getText()
{
return text.toString();
}
@Override
public boolean updateTime(double curTime)
{
return false;
}
}

View file

@ -0,0 +1,187 @@
/*
* 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 January 26, 2004, 5:25 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Ellipse extends ShapeElement
{
public static final String TAG_NAME = "ellipse";
float cx = 0.0f;
float cy = 0.0f;
float rx = 0.0f;
float ry = 0.0f;
Ellipse2D.Float ellipse = new Ellipse2D.Float();
/**
* Creates a new instance of Rect
*/
public Ellipse()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("cx")))
{
cx = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("cy")))
{
cy = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("rx")))
{
rx = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("ry")))
{
ry = sty.getFloatValueWithUnits();
}
ellipse.setFrame(cx - rx, cy - ry, rx * 2f, ry * 2f);
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
beginLayer(g);
renderShape(g, ellipse);
finishLayer(g);
}
@Override
public Shape getShape()
{
return shapeToParent(ellipse);
}
@Override
public Rectangle2D getBoundingBox() throws SVGException
{
return boundsToParent(includeStrokeInBounds(ellipse.getBounds2D()));
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
boolean changeState = super.updateTime(curTime);
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getPres(sty.setName("cx")))
{
float newCx = sty.getFloatValueWithUnits();
if (newCx != cx)
{
cx = newCx;
shapeChange = true;
}
}
if (getPres(sty.setName("cy")))
{
float newCy = sty.getFloatValueWithUnits();
if (newCy != cy)
{
cy = newCy;
shapeChange = true;
}
}
if (getPres(sty.setName("rx")))
{
float newRx = sty.getFloatValueWithUnits();
if (newRx != rx)
{
rx = newRx;
shapeChange = true;
}
}
if (getPres(sty.setName("ry")))
{
float newRy = sty.getFloatValueWithUnits();
if (newRy != ry)
{
ry = newRy;
shapeChange = true;
}
}
if (shapeChange)
{
build();
// ellipse.setFrame(cx - rx, cy - ry, rx * 2f, ry * 2f);
// return true;
}
return changeState || shapeChange;
}
}

View file

@ -0,0 +1,123 @@
/*
* 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 March 18, 2004, 6:52 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class FeDistantLight extends FeLight
{
public static final String TAG_NAME = "fedistantlight";
float azimuth = 0f;
float elevation = 0f;
/**
* Creates a new instance of FillElement
*/
public FeDistantLight()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("azimuth")))
{
azimuth = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("elevation")))
{
elevation = sty.getFloatValueWithUnits();
}
}
public float getAzimuth()
{
return azimuth;
}
public float getElevation()
{
return elevation;
}
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean stateChange = false;
if (getPres(sty.setName("azimuth")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != azimuth)
{
azimuth = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("elevation")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != elevation)
{
elevation = newVal;
stateChange = true;
}
}
return stateChange;
}
}

View file

@ -0,0 +1,117 @@
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Rectangle;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.util.Arrays;
import java.util.List;
public class FeGaussianBlur extends FilterEffects
{
public static final String TAG_NAME = "fegaussianblur";
private float[] stdDeviation;
private float xCurrent;
private float yCurrent;
private ConvolveOp xBlur;
private ConvolveOp yBlur;
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
stdDeviation = new float[]{0f};
if (getPres(sty.setName("stdDeviation")))
{
stdDeviation = sty.getFloatList();
}
xBlur = null;
yBlur = null;
}
@Override
public List<FilterOp> getOperations(Rectangle inputBounds, float xScale, float yScale)
{
float xSigma = xScale * stdDeviation[0];
float ySigma = yScale * stdDeviation[Math.min(stdDeviation.length - 1, 1)];
return Arrays.asList(
xSigma > 0
? getGaussianBlurFilter(inputBounds, xSigma, true)
: null,
ySigma > 0
? getGaussianBlurFilter(inputBounds, ySigma, false)
: null
);
}
public FilterOp getGaussianBlurFilter(Rectangle inputBounds, float sigma, boolean horizontal)
{
int multiplier = 2;
float radius = 2f * sigma + 1;
int size = (int) Math.ceil(radius * multiplier) + 1;
if (horizontal && (xBlur == null || xCurrent != sigma)
|| !horizontal && (yBlur == null || yCurrent != sigma))
{
if (horizontal)
{
xCurrent = sigma;
} else
{
yCurrent = sigma;
}
float[] data = new float[size];
float radius2 = radius * radius;
float twoSigmaSquare = 2.0f * sigma * sigma;
float sigmaRoot = (float) Math.sqrt(twoSigmaSquare * Math.PI);
float total = 0.0f;
float middle = size / 2f;
for (int i = 0; i < size; i++)
{
float distance = middle - i;
distance *= distance;
data[i] = distance > radius2
? 0
: (float) Math.exp(-distance / twoSigmaSquare) / sigmaRoot;
total += data[i];
}
for (int i = 0; i < data.length; i++)
{
data[i] /= total;
}
if (horizontal)
{
xBlur = new ConvolveOp(new Kernel(size, 1, data), ConvolveOp.EDGE_NO_OP, null);
} else
{
yBlur = new ConvolveOp(new Kernel(1, size, data), ConvolveOp.EDGE_NO_OP, null);
}
}
Rectangle dstBounds = new Rectangle(inputBounds);
if (horizontal)
{
dstBounds.grow(size, 0);
} else
{
dstBounds.grow(0, size);
}
return new FilterOp(horizontal ? xBlur : yBlur, dstBounds);
}
}

View file

@ -0,0 +1,59 @@
/*
* 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 March 18, 2004, 6:52 AM
*/
package org.xbib.graphics.svg;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
abstract public class FeLight extends FilterEffects
{
public static final String TAG_NAME = "feLight";
/**
* Creates a new instance of FillElement
*/
public FeLight()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
}

View file

@ -0,0 +1,146 @@
/*
* 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 March 18, 2004, 6:52 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class FePointLight extends FeLight
{
public static final String TAG_NAME = "fepointlight";
float x = 0f;
float y = 0f;
float z = 0f;
/**
* Creates a new instance of FillElement
*/
public FePointLight()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("x")))
{
x = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("y")))
{
y = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("z")))
{
z = sty.getFloatValueWithUnits();
}
}
@Override
public float getX()
{
return x;
}
@Override
public float getY()
{
return y;
}
public float getZ()
{
return z;
}
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean stateChange = false;
if (getPres(sty.setName("x")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != x)
{
x = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("y")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != y)
{
y = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("z")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != z)
{
z = newVal;
stateChange = true;
}
}
return stateChange;
}
}

View file

@ -0,0 +1,244 @@
/*
* 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 March 18, 2004, 6:52 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class FeSpotLight extends FeLight
{
public static final String TAG_NAME = "fespotlight";
float x = 0f;
float y = 0f;
float z = 0f;
float pointsAtX = 0f;
float pointsAtY = 0f;
float pointsAtZ = 0f;
float specularComponent = 0f;
float limitingConeAngle = 0f;
/**
* Creates a new instance of FillElement
*/
public FeSpotLight()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("x")))
{
x = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("y")))
{
y = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("z")))
{
z = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("pointsAtX")))
{
pointsAtX = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("pointsAtY")))
{
pointsAtY = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("pointsAtZ")))
{
pointsAtZ = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("specularComponent")))
{
specularComponent = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("limitingConeAngle")))
{
limitingConeAngle = sty.getFloatValueWithUnits();
}
}
@Override
public float getX()
{
return x;
}
@Override
public float getY()
{
return y;
}
public float getZ()
{
return z;
}
public float getPointsAtX()
{
return pointsAtX;
}
public float getPointsAtY()
{
return pointsAtY;
}
public float getPointsAtZ()
{
return pointsAtZ;
}
public float getSpecularComponent()
{
return specularComponent;
}
public float getLimitingConeAngle()
{
return limitingConeAngle;
}
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean stateChange = false;
if (getPres(sty.setName("x")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != x)
{
x = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("y")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != y)
{
y = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("z")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != z)
{
z = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("pointsAtX")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != pointsAtX)
{
pointsAtX = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("pointsAtY")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != pointsAtY)
{
pointsAtY = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("pointsAtZ")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != pointsAtZ)
{
pointsAtZ = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("specularComponent")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != specularComponent)
{
specularComponent = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("limitingConeAngle")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != limitingConeAngle)
{
limitingConeAngle = newVal;
stateChange = true;
}
}
return stateChange;
}
}

View file

@ -0,0 +1,64 @@
/*
* 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 March 18, 2004, 6:52 AM
*/
package org.xbib.graphics.svg;
import java.awt.*;
import java.awt.geom.*;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
abstract public class FillElement extends SVGElement
{
/**
* Creates a new instance of FillElement
*/
public FillElement()
{
}
/**
* Requests the paint defined by this element. Passes in information to
* allow paint to be customized
*
* @param bounds - bounding box of shape being rendered
* @param xform - The current transformation that the shape is being
* rendered under.
* @return paint object
*/
abstract public Paint getPaint(Rectangle2D bounds, AffineTransform xform);
}

View file

@ -0,0 +1,287 @@
/*
* 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 March 18, 2004, 6:52 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.geom.Point2D;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Filter extends SVGElement
{
public static final String TAG_NAME = "filter";
public static final int FU_OBJECT_BOUNDING_BOX = 0;
public static final int FU_USER_SPACE_ON_USE = 1;
protected int filterUnits = FU_OBJECT_BOUNDING_BOX;
public static final int PU_OBJECT_BOUNDING_BOX = 0;
public static final int PU_USER_SPACE_ON_USE = 1;
protected int primitiveUnits = PU_OBJECT_BOUNDING_BOX;
float x = 0f;
float y = 0f;
float width = 1f;
float height = 1f;
Point2D filterRes = new Point2D.Double();
URL href = null;
final ArrayList<FilterEffects> filterEffects = new ArrayList<>();
/**
* Creates a new instance of FillElement
*/
public Filter()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Called after the start element but before the end element to indicate
* each child tag that has been processed
*/
@Override
public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
{
super.loaderAddChild(helper, child);
if (child instanceof FilterEffects)
{
filterEffects.add((FilterEffects) child);
}
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
String strn;
if (getPres(sty.setName("filterUnits")))
{
strn = sty.getStringValue().toLowerCase();
if (strn.equals("userspaceonuse"))
{
filterUnits = FU_USER_SPACE_ON_USE;
} else
{
filterUnits = FU_OBJECT_BOUNDING_BOX;
}
}
if (getPres(sty.setName("primitiveUnits")))
{
strn = sty.getStringValue().toLowerCase();
if (strn.equals("userspaceonuse"))
{
primitiveUnits = PU_USER_SPACE_ON_USE;
} else
{
primitiveUnits = PU_OBJECT_BOUNDING_BOX;
}
}
if (getPres(sty.setName("x")))
{
x = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("y")))
{
y = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("width")))
{
width = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("height")))
{
height = sty.getFloatValueWithUnits();
}
try
{
if (getPres(sty.setName("xlink:href")))
{
URI src = sty.getURIValue(getXMLBase());
href = src.toURL();
}
} catch (Exception e)
{
throw new SVGException(e);
}
}
public float getX()
{
return x;
}
public float getY()
{
return y;
}
public float getWidth()
{
return width;
}
public float getHeight()
{
return height;
}
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean stateChange = false;
if (getPres(sty.setName("x")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != x)
{
x = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("y")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != y)
{
y = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("width")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != width)
{
width = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("height")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != height)
{
height = newVal;
stateChange = true;
}
}
try
{
if (getPres(sty.setName("xlink:href")))
{
URI src = sty.getURIValue(getXMLBase());
URL newVal = src.toURL();
if (!newVal.equals(href))
{
href = newVal;
stateChange = true;
}
}
} catch (Exception e)
{
throw new SVGException(e);
}
if (getPres(sty.setName("filterUnits")))
{
int newVal;
String strn = sty.getStringValue().toLowerCase();
if (strn.equals("userspaceonuse"))
{
newVal = FU_USER_SPACE_ON_USE;
} else
{
newVal = FU_OBJECT_BOUNDING_BOX;
}
if (newVal != filterUnits)
{
filterUnits = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("primitiveUnits")))
{
int newVal;
String strn = sty.getStringValue().toLowerCase();
if (strn.equals("userspaceonuse"))
{
newVal = PU_USER_SPACE_ON_USE;
} else
{
newVal = PU_OBJECT_BOUNDING_BOX;
}
if (newVal != filterUnits)
{
primitiveUnits = newVal;
stateChange = true;
}
}
return stateChange;
}
}

View file

@ -0,0 +1,273 @@
/*
* 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 March 18, 2004, 6:52 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Rectangle;
import java.awt.image.BufferedImageOp;
import java.net.URI;
import java.net.URL;
import java.util.List;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public abstract class FilterEffects extends SVGElement
{
public static final String TAG_NAME = "filtereffects";
public static final int FP_SOURCE_GRAPHIC = 0;
public static final int FP_SOURCE_ALPHA = 1;
public static final int FP_BACKGROUND_IMAGE = 2;
public static final int FP_BACKGROUND_ALPHA = 3;
public static final int FP_FILL_PAINT = 4;
public static final int FP_STROKE_PAINT = 5;
public static final int FP_CUSTOM = 5;
private int filterPrimitiveTypeIn;
private String filterPrimitiveRefIn;
float x = 0f;
float y = 0f;
float width = 1f;
float height = 1f;
URL href = null;
/**
* Creates a new instance of FillElement
*/
public FilterEffects()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Called after the start element but before the end element to indicate
* each child tag that has been processed
*/
@Override
public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
{
super.loaderAddChild(helper, child);
if (child instanceof FilterEffects)
{
// filterEffects.add(child);
}
}
@Override
protected void build() throws SVGException
{
super.build();
/*StyleAttribute sty = new StyleAttribute();
String strn;
if (getPres(sty.setName("filterUnits")))
{
strn = sty.getStringValue().toLowerCase();
if (strn.equals("userspaceonuse")) filterUnits = FU_USER_SPACE_ON_USE;
else filterUnits = FU_OBJECT_BOUNDING_BOX;
}
if (getPres(sty.setName("primitiveUnits")))
{
strn = sty.getStringValue().toLowerCase();
if (strn.equals("userspaceonuse")) primitiveUnits = PU_USER_SPACE_ON_USE;
else primitiveUnits = PU_OBJECT_BOUNDING_BOX;
}
if (getPres(sty.setName("x"))) x = sty.getFloatValue();
if (getPres(sty.setName("y"))) y = sty.getFloatValue();
if (getPres(sty.setName("width"))) width = sty.getFloatValue();
if (getPres(sty.setName("height"))) height = sty.getFloatValue();
try {
if (getPres(sty.setName("xlink:href")))
{
URI src = sty.getURIValue(getXMLBase());
href = src.toURL();
}
}
catch (Exception e)
{
throw new SVGException(e);
}
*/
}
public List<FilterOp> getOperations(Rectangle bounds, float xScale, float yScale) {
return null;
}
public float getX()
{
return x;
}
public float getY()
{
return y;
}
public float getWidth()
{
return width;
}
public float getHeight()
{
return height;
}
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean stateChange = false;
if (getPres(sty.setName("x")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != x)
{
x = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("y")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != y)
{
y = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("width")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != width)
{
width = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("height")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != height)
{
height = newVal;
stateChange = true;
}
}
try
{
if (getPres(sty.setName("xlink:href")))
{
URI src = sty.getURIValue(getXMLBase());
URL newVal = src.toURL();
if (!newVal.equals(href))
{
href = newVal;
stateChange = true;
}
}
} catch (Exception e)
{
throw new SVGException(e);
}
/*
if (getPres(sty.setName("filterUnits")))
{
int newVal;
String strn = sty.getStringValue().toLowerCase();
if (strn.equals("userspaceonuse")) newVal = FU_USER_SPACE_ON_USE;
else newVal = FU_OBJECT_BOUNDING_BOX;
if (newVal != filterUnits)
{
filterUnits = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("primitiveUnits")))
{
int newVal;
String strn = sty.getStringValue().toLowerCase();
if (strn.equals("userspaceonuse")) newVal = PU_USER_SPACE_ON_USE;
else newVal = PU_OBJECT_BOUNDING_BOX;
if (newVal != filterUnits)
{
primitiveUnits = newVal;
stateChange = true;
}
}
*/
return stateChange;
}
public static class FilterOp {
public final BufferedImageOp op;
public final Rectangle requiredImageBounds;
public FilterOp(BufferedImageOp op, Rectangle requiredImageBounds) {
this.op = op;
this.requiredImageBounds = requiredImageBounds;
}
}
}

View file

@ -0,0 +1,292 @@
/*
* 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 February 20, 2004, 10:00 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.util.HashMap;
/**
* Implements an embedded font.
*
* SVG specification: http://www.w3.org/TR/SVG/fonts.html
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Font extends SVGElement
{
public static final String TAG_NAME = "font";
int horizOriginX = 0;
int horizOriginY = 0;
int horizAdvX = -1; //Must be specified
int vertOriginX = -1; //Defaults to horizAdvX / 2
int vertOriginY = -1; //Defaults to font's ascent
int vertAdvY = -1; //Defaults to one 'em'. See font-face
FontFace fontFace = null;
MissingGlyph missingGlyph = null;
final HashMap<String, SVGElement> glyphs = new HashMap<String, SVGElement>();
/**
* Creates a new instance of Font
*/
public Font()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Called after the start element but before the end element to indicate
* each child tag that has been processed
*/
@Override
public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
{
super.loaderAddChild(helper, child);
if (child instanceof Glyph)
{
glyphs.put(((Glyph) child).getUnicode(), child);
} else if (child instanceof MissingGlyph)
{
missingGlyph = (MissingGlyph) child;
} else if (child instanceof FontFace)
{
fontFace = (FontFace) child;
}
}
@Override
public void loaderEndElement(SVGLoaderHelper helper) throws SVGParseException
{
super.loaderEndElement(helper);
//build();
helper.universe.registerFont(this);
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("horiz-origin-x")))
{
horizOriginX = sty.getIntValue();
}
if (getPres(sty.setName("horiz-origin-y")))
{
horizOriginY = sty.getIntValue();
}
if (getPres(sty.setName("horiz-adv-x")))
{
horizAdvX = sty.getIntValue();
}
if (getPres(sty.setName("vert-origin-x")))
{
vertOriginX = sty.getIntValue();
}
if (getPres(sty.setName("vert-origin-y")))
{
vertOriginY = sty.getIntValue();
}
if (getPres(sty.setName("vert-adv-y")))
{
vertAdvY = sty.getIntValue();
}
}
public FontFace getFontFace()
{
return fontFace;
}
public void setFontFace(FontFace face)
{
fontFace = face;
}
public MissingGlyph getGlyph(String unicode)
{
Glyph retVal = (Glyph) glyphs.get(unicode);
if (retVal == null)
{
return missingGlyph;
}
return retVal;
}
public int getHorizOriginX()
{
return horizOriginX;
}
public int getHorizOriginY()
{
return horizOriginY;
}
public int getHorizAdvX()
{
return horizAdvX;
}
public int getVertOriginX()
{
if (vertOriginX != -1)
{
return vertOriginX;
}
vertOriginX = getHorizAdvX() / 2;
return vertOriginX;
}
public int getVertOriginY()
{
if (vertOriginY != -1)
{
return vertOriginY;
}
vertOriginY = fontFace.getAscent();
return vertOriginY;
}
public int getVertAdvY()
{
if (vertAdvY != -1)
{
return vertAdvY;
}
vertAdvY = fontFace.getUnitsPerEm();
return vertAdvY;
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
//Fonts can't change
return false;
/*
if (trackManager.getNumTracks() == 0) return false;
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean stateChange = false;
if (getPres(sty.setName("horiz-origin-x")))
{
int newVal = sty.getIntValue();
if (newVal != horizOriginX)
{
horizOriginX = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("horiz-origin-y")))
{
int newVal = sty.getIntValue();
if (newVal != horizOriginY)
{
horizOriginY = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("horiz-adv-x")))
{
int newVal = sty.getIntValue();
if (newVal != horizAdvX)
{
horizAdvX = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("vert-origin-x")))
{
int newVal = sty.getIntValue();
if (newVal != vertOriginX)
{
vertOriginX = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("vert-origin-y")))
{
int newVal = sty.getIntValue();
if (newVal != vertOriginY)
{
vertOriginY = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("vert-adv-y")))
{
int newVal = sty.getIntValue();
if (newVal != vertAdvY)
{
vertAdvY = newVal;
stateChange = true;
}
}
return shapeChange;
*/
}
}

View file

@ -0,0 +1,319 @@
/*
* 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 February 20, 2004, 10:00 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
/**
* Implements an embedded font.
*
* SVG specification: http://www.w3.org/TR/SVG/fonts.html
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class FontFace extends SVGElement
{
public static final String TAG_NAME = "fontface";
String fontFamily;
/**
* Em size of coordinate system font is defined in
*/
private int unitsPerEm = 1000;
private int ascent = -1;
private int descent = -1;
private int accentHeight = -1;
private int underlinePosition = -1;
private int underlineThickness = -1;
private int strikethroughPosition = -1;
private int strikethroughThickness = -1;
private int overlinePosition = -1;
private int overlineThickness = -1;
/**
* Creates a new instance of Font
*/
public FontFace()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("font-family")))
{
fontFamily = sty.getStringValue();
}
if (getPres(sty.setName("units-per-em")))
{
unitsPerEm = sty.getIntValue();
}
if (getPres(sty.setName("ascent")))
{
ascent = sty.getIntValue();
}
if (getPres(sty.setName("descent")))
{
descent = sty.getIntValue();
}
if (getPres(sty.setName("accent-height")))
{
accentHeight = sty.getIntValue();
}
if (getPres(sty.setName("underline-position")))
{
underlinePosition = sty.getIntValue();
}
if (getPres(sty.setName("underline-thickness")))
{
underlineThickness = sty.getIntValue();
}
if (getPres(sty.setName("strikethrough-position")))
{
strikethroughPosition = sty.getIntValue();
}
if (getPres(sty.setName("strikethrough-thickenss")))
{
strikethroughThickness = sty.getIntValue();
}
if (getPres(sty.setName("overline-position")))
{
overlinePosition = sty.getIntValue();
}
if (getPres(sty.setName("overline-thickness")))
{
overlineThickness = sty.getIntValue();
}
}
public String getFontFamily()
{
return fontFamily;
}
public int getUnitsPerEm()
{
return unitsPerEm;
}
public int getAscent()
{
if (ascent == -1)
{
ascent = unitsPerEm - ((Font) parent).getVertOriginY();
}
return ascent;
}
public int getDescent()
{
if (descent == -1)
{
descent = ((Font) parent).getVertOriginY();
}
return descent;
}
public int getAccentHeight()
{
if (accentHeight == -1)
{
accentHeight = getAscent();
}
return accentHeight;
}
public int getUnderlinePosition()
{
if (underlinePosition == -1)
{
underlinePosition = unitsPerEm * 5 / 6;
}
return underlinePosition;
}
public int getUnderlineThickness()
{
if (underlineThickness == -1)
{
underlineThickness = unitsPerEm / 20;
}
return underlineThickness;
}
public int getStrikethroughPosition()
{
if (strikethroughPosition == -1)
{
strikethroughPosition = unitsPerEm * 3 / 6;
}
return strikethroughPosition;
}
public int getStrikethroughThickness()
{
if (strikethroughThickness == -1)
{
strikethroughThickness = unitsPerEm / 20;
}
return strikethroughThickness;
}
public int getOverlinePosition()
{
if (overlinePosition == -1)
{
overlinePosition = unitsPerEm * 5 / 6;
}
return overlinePosition;
}
public int getOverlineThickness()
{
if (overlineThickness == -1)
{
overlineThickness = unitsPerEm / 20;
}
return overlineThickness;
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime)
{
//Fonts can't change
return false;
}
/**
* @param unitsPerEm the unitsPerEm to set
*/
public void setUnitsPerEm(int unitsPerEm)
{
this.unitsPerEm = unitsPerEm;
}
/**
* @param ascent the ascent to set
*/
public void setAscent(int ascent)
{
this.ascent = ascent;
}
/**
* @param descent the descent to set
*/
public void setDescent(int descent)
{
this.descent = descent;
}
/**
* @param accentHeight the accentHeight to set
*/
public void setAccentHeight(int accentHeight)
{
this.accentHeight = accentHeight;
}
/**
* @param underlinePosition the underlinePosition to set
*/
public void setUnderlinePosition(int underlinePosition)
{
this.underlinePosition = underlinePosition;
}
/**
* @param underlineThickness the underlineThickness to set
*/
public void setUnderlineThickness(int underlineThickness)
{
this.underlineThickness = underlineThickness;
}
/**
* @param strikethroughPosition the strikethroughPosition to set
*/
public void setStrikethroughPosition(int strikethroughPosition)
{
this.strikethroughPosition = strikethroughPosition;
}
/**
* @param strikethroughThickness the strikethroughThickness to set
*/
public void setStrikethroughThickness(int strikethroughThickness)
{
this.strikethroughThickness = strikethroughThickness;
}
/**
* @param overlinePosition the overlinePosition to set
*/
public void setOverlinePosition(int overlinePosition)
{
this.overlinePosition = overlinePosition;
}
/**
* @param overlineThickness the overlineThickness to set
*/
public void setOverlineThickness(int overlineThickness)
{
this.overlineThickness = overlineThickness;
}
}

View file

@ -0,0 +1,102 @@
/*
* 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 February 20, 2004, 10:00 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
/**
* Implements an embedded font.
*
* SVG specification: http://www.w3.org/TR/SVG/fonts.html
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Glyph extends MissingGlyph
{
public static final String TAG_NAME = "missingglyph";
/**
* One or more characters indicating the unicode sequence that denotes this
* glyph.
*/
String unicode;
/**
* Creates a new instance of Font
*/
public Glyph()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("unicode")))
{
unicode = sty.getStringValue();
}
}
public String getUnicode()
{
return unicode;
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
//Fonts can't change
return false;
}
}

View file

@ -0,0 +1,367 @@
/*
* 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 January 26, 2004, 3:25 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.net.URI;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
abstract public class Gradient extends FillElement
{
public static final String TAG_NAME = "gradient";
public static final int SM_PAD = 0;
public static final int SM_REPEAT = 1;
public static final int SM_REFLECT = 2;
int spreadMethod = SM_PAD;
public static final int GU_OBJECT_BOUNDING_BOX = 0;
public static final int GU_USER_SPACE_ON_USE = 1;
protected int gradientUnits = GU_OBJECT_BOUNDING_BOX;
//Either this gradient contains a list of stops, or it will take it's
// stops from the referenced gradient
ArrayList<Stop> stops = new ArrayList<Stop>();
URI stopRef = null;
protected AffineTransform gradientTransform = null;
//Cache arrays of stop values here
float[] stopFractions;
Color[] stopColors;
/**
* Creates a new instance of Gradient
*/
public Gradient()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Called after the start element but before the end element to indicate
* each child tag that has been processed
*/
@Override
public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
{
super.loaderAddChild(helper, child);
if (!(child instanceof Stop))
{
return;
}
appendStop((Stop) child);
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
String strn;
if (getPres(sty.setName("spreadMethod")))
{
strn = sty.getStringValue().toLowerCase();
if (strn.equals("repeat"))
{
spreadMethod = SM_REPEAT;
} else if (strn.equals("reflect"))
{
spreadMethod = SM_REFLECT;
} else
{
spreadMethod = SM_PAD;
}
}
if (getPres(sty.setName("gradientUnits")))
{
strn = sty.getStringValue().toLowerCase();
if (strn.equals("userspaceonuse"))
{
gradientUnits = GU_USER_SPACE_ON_USE;
} else
{
gradientUnits = GU_OBJECT_BOUNDING_BOX;
}
}
if (getPres(sty.setName("gradientTransform")))
{
gradientTransform = parseTransform(sty.getStringValue());
}
//If we still don't have one, set it to identity
if (gradientTransform == null)
{
gradientTransform = new AffineTransform();
}
//Check to see if we're using our own stops or referencing someone else's
if (getPres(sty.setName("xlink:href")))
{
try
{
stopRef = sty.getURIValue(getXMLBase());
//System.err.println("Gradient: " + sty.getStringValue() + ", " + getXMLBase() + ", " + src);
// URI src = getXMLBase().resolve(href);
// stopRef = (Gradient)diagram.getUniverse().getElement(src);
} catch (Exception e)
{
throw new SVGException("Could not resolve relative URL in Gradient: " + sty.getStringValue() + ", " + getXMLBase(), e);
}
}
}
private void buildStops()
{
ArrayList<Stop> stopList = new ArrayList<Stop>(stops);
stopList.sort(new Comparator<Stop>(){
public int compare(Stop o1, Stop o2)
{
return Float.compare(o1.offset, o2.offset);
}
});
//Remove doubles
for (int i = stopList.size() - 2; i >= 0; --i)
{
if (stopList.get(i + 1).offset == stopList.get(i).offset)
{
stopList.remove(i + 1);
}
}
stopFractions = new float[stopList.size()];
stopColors = new Color[stopList.size()];
int idx = 0;
for (Stop stop : stopList)
{
int stopColorVal = stop.color.getRGB();
Color stopColor = new Color((stopColorVal >> 16) & 0xff, (stopColorVal >> 8) & 0xff, stopColorVal & 0xff, clamp((int) (stop.opacity * 255), 0, 255));
stopColors[idx] = stopColor;
stopFractions[idx] = stop.offset;
idx++;
}
}
public float[] getStopFractions()
{
if (stopRef != null)
{
Gradient grad = (Gradient) diagram.getUniverse().getElement(stopRef);
return grad.getStopFractions();
}
if (stopFractions != null)
{
return stopFractions;
}
buildStops();
return stopFractions;
}
public Color[] getStopColors()
{
if (stopRef != null)
{
Gradient grad = (Gradient) diagram.getUniverse().getElement(stopRef);
return grad.getStopColors();
}
if (stopColors != null)
{
return stopColors;
}
buildStops();
return stopColors;
}
// public void setStops(Color[] colors, float[] fractions)
// {
// if (colors.length != fractions.length)
// {
// throw new IllegalArgumentException();
// }
//
// this.stopColors = colors;
// this.stopFractions = fractions;
// stopRef = null;
// }
private int clamp(int val, int min, int max)
{
if (val < min)
{
return min;
}
if (val > max)
{
return max;
}
return val;
}
public void setStopRef(URI grad)
{
stopRef = grad;
}
public void appendStop(Stop stop)
{
stops.add(stop);
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
boolean stateChange = false;
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
String strn;
if (getPres(sty.setName("spreadMethod")))
{
int newVal;
strn = sty.getStringValue().toLowerCase();
if (strn.equals("repeat"))
{
newVal = SM_REPEAT;
} else if (strn.equals("reflect"))
{
newVal = SM_REFLECT;
} else
{
newVal = SM_PAD;
}
if (spreadMethod != newVal)
{
spreadMethod = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("gradientUnits")))
{
int newVal;
strn = sty.getStringValue().toLowerCase();
if (strn.equals("userspaceonuse"))
{
newVal = GU_USER_SPACE_ON_USE;
} else
{
newVal = GU_OBJECT_BOUNDING_BOX;
}
if (newVal != gradientUnits)
{
gradientUnits = newVal;
stateChange = true;
}
}
if (getPres(sty.setName("gradientTransform")))
{
AffineTransform newVal = parseTransform(sty.getStringValue());
if (newVal != null && newVal.equals(gradientTransform))
{
gradientTransform = newVal;
stateChange = true;
}
}
//Check to see if we're using our own stops or referencing someone else's
if (getPres(sty.setName("xlink:href")))
{
try
{
URI newVal = sty.getURIValue(getXMLBase());
if ((newVal == null && stopRef != null) || !newVal.equals(stopRef))
{
stopRef = newVal;
stateChange = true;
}
} catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse xlink:href", e);
}
}
//Check stops, if any
for (Stop stop : stops) {
if (stop.updateTime(curTime))
{
stateChange = true;
stopFractions = null;
stopColors = null;
}
}
return stateChange;
}
}

View file

@ -0,0 +1,340 @@
/*
* 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 January 26, 2004, 1:56 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import java.util.List;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Group extends ShapeElement
{
public static final String TAG_NAME = "group";
//Cache bounding box for faster clip testing
Rectangle2D boundingBox;
Shape cachedShape;
/**
* Creates a new instance of Stop
*/
public Group()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Called after the start element but before the end element to indicate
* each child tag that has been processed
*/
@Override
public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
{
super.loaderAddChild(helper, child);
}
protected boolean outsideClip(Graphics2D g) throws SVGException
{
Shape clip = g.getClip();
if (clip == null)
{
return false;
}
//g.getClipBounds(clipBounds);
Rectangle2D rect = getBoundingBox();
if (clip.intersects(rect))
{
return false;
}
return true;
}
@Override
protected void doPick(Point2D point, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
{
Point2D xPoint = new Point2D.Double(point.getX(), point.getY());
if (xform != null)
{
try
{
xform.inverseTransform(point, xPoint);
} catch (NoninvertibleTransformException ex)
{
throw new SVGException(ex);
}
}
for (SVGElement ele : children) {
if (ele instanceof RenderableElement)
{
RenderableElement rendEle = (RenderableElement) ele;
rendEle.pick(xPoint, boundingBox, retVec);
}
}
}
@Override
protected void doPick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
{
if (xform != null)
{
ltw = new AffineTransform(ltw);
ltw.concatenate(xform);
}
for (SVGElement ele : children) {
if (ele instanceof RenderableElement)
{
RenderableElement rendEle = (RenderableElement) ele;
rendEle.pick(pickArea, ltw, boundingBox, retVec);
}
}
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
//Don't process if not visible
StyleAttribute styleAttrib = new StyleAttribute();
//Visibility can be overridden by children
if (getStyle(styleAttrib.setName("display")))
{
if (styleAttrib.getStringValue().equals("none"))
{
return;
}
}
//Do not process offscreen groups
boolean ignoreClip = diagram.ignoringClipHeuristic();
// if (!ignoreClip && outsideClip(g))
// {
// return;
// }
beginLayer(g);
Iterator<SVGElement> it = children.iterator();
// try
// {
// g.getClipBounds(clipBounds);
// }
// catch (Exception e)
// {
// //For some reason, getClipBounds can throw a null pointer exception for
// // some types of Graphics2D
// ignoreClip = true;
// }
Shape clip = g.getClip();
while (it.hasNext())
{
SVGElement ele = it.next();
if (ele instanceof RenderableElement)
{
RenderableElement rendEle = (RenderableElement) ele;
// if (shapeEle == null) continue;
if (!(ele instanceof Group))
{
//Skip if clipping area is outside our bounds
if (!ignoreClip && clip != null
&& !clip.intersects(rendEle.getBoundingBox()))
{
continue;
}
}
rendEle.render(g);
}
}
finishLayer(g);
}
/**
* Retrieves the cached bounding box of this group
*/
@Override
public Shape getShape()
{
if (cachedShape == null)
{
calcShape();
}
return cachedShape;
}
public void calcShape()
{
Area retShape = new Area();
for (SVGElement ele : children) {
if (ele instanceof ShapeElement)
{
ShapeElement shpEle = (ShapeElement) ele;
Shape shape = shpEle.getShape();
if (shape != null)
{
retShape.add(new Area(shape));
}
}
}
cachedShape = shapeToParent(retShape);
}
/**
* Retrieves the cached bounding box of this group
*/
@Override
public Rectangle2D getBoundingBox() throws SVGException
{
if (boundingBox == null)
{
calcBoundingBox();
}
// calcBoundingBox();
return boundingBox;
}
/**
* Recalculates the bounding box by taking the union of the bounding boxes
* of all children. Caches the result.
* @throws SVGException
*/
public void calcBoundingBox() throws SVGException
{
Rectangle2D retRect = null;
for (SVGElement ele : children) {
if (ele instanceof RenderableElement)
{
RenderableElement rendEle = (RenderableElement) ele;
Rectangle2D bounds = rendEle.getBoundingBox();
if (bounds != null && (bounds.getWidth() != 0 || bounds.getHeight() != 0))
{
if (retRect == null)
{
retRect = bounds;
}
else
{
if (retRect.getWidth() != 0 || retRect.getHeight() != 0)
{
retRect = retRect.createUnion(bounds);
}
}
}
}
}
// if (xform != null)
// {
// retRect = xform.createTransformedShape(retRect).getBounds2D();
// }
//If no contents, use degenerate rectangle
if (retRect == null)
{
retRect = new Rectangle2D.Float();
}
boundingBox = boundsToParent(retRect);
}
@Override
public boolean updateTime(double curTime) throws SVGException
{
boolean changeState = super.updateTime(curTime);
Iterator<SVGElement> it = children.iterator();
//Distribute message to all members of this group
while (it.hasNext())
{
SVGElement ele = it.next();
boolean updateVal = ele.updateTime(curTime);
if (updateVal && ele instanceof RenderableElement)
{
((RenderableElement) ele).setBufferImage(null);
}
changeState = changeState || updateVal;
//Update our shape if shape aware children change
if (ele instanceof ShapeElement)
{
cachedShape = null;
}
if (ele instanceof RenderableElement)
{
boundingBox = null;
}
}
if (changeState)
{
setBufferImage(null);
}
return changeState;
}
}

View file

@ -0,0 +1,89 @@
/*
* 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 February 20, 2004, 10:00 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
/**
*
* @author kitfox
*/
public class Hkern extends SVGElement
{
public static final String TAG_NAME = "hkern";
String u1;
String u2;
int k;
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
//Read glyph spacing info
if (getPres(sty.setName("u1")))
{
u1 = sty.getStringValue();
}
if (getPres(sty.setName("u2")))
{
u2 = sty.getStringValue();
}
if (getPres(sty.setName("k")))
{
k = sty.getIntValue();
}
}
@Override
public boolean updateTime(double curTime) throws SVGException
{
//Fonts can't change
return false;
}
}

View file

@ -0,0 +1,398 @@
/*
* 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 February 20, 2004, 10:00 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.app.data.Handler;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.net.URI;
import java.net.URL;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Implements an image.
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class ImageSVG extends RenderableElement
{
public static final String TAG_NAME = "image";
float x = 0f;
float y = 0f;
float width = 0f;
float height = 0f;
// BufferedImage href = null;
URL imageSrc = null;
AffineTransform xform;
Rectangle2D bounds;
/**
* Creates a new instance of Font
*/
public ImageSVG()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("x")))
{
x = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("y")))
{
y = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("width")))
{
width = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("height")))
{
height = sty.getFloatValueWithUnits();
}
try
{
if (getPres(sty.setName("xlink:href")))
{
URI src = sty.getURIValue(getXMLBase());
if ("data".equals(src.getScheme()))
{
imageSrc = new URL(null, src.toASCIIString(), new Handler());
}
else if (!diagram.getUniverse().isImageDataInlineOnly())
{
try
{
imageSrc = src.toURL();
} catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse xlink:href " + src, e);
imageSrc = null;
}
}
}
} catch (Exception e)
{
throw new SVGException(e);
}
if (imageSrc != null)
{
diagram.getUniverse().registerImage(imageSrc);
//Set widths if not set
BufferedImage img = diagram.getUniverse().getImage(imageSrc);
if (img == null)
{
xform = new AffineTransform();
bounds = new Rectangle2D.Float();
return;
}
if (width == 0)
{
width = img.getWidth();
}
if (height == 0)
{
height = img.getHeight();
}
//Determine image xform
xform = new AffineTransform();
xform.translate(this.x, this.y);
xform.scale(this.width / img.getWidth(), this.height / img.getHeight());
}
bounds = new Rectangle2D.Float(this.x, this.y, this.width, this.height);
}
public float getX()
{
return x;
}
public float getY()
{
return y;
}
public float getWidth()
{
return width;
}
public float getHeight()
{
return height;
}
@Override
protected void doPick(Point2D point, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
{
if (getBoundingBox().contains(point))
{
retVec.add(getPath(null));
}
}
@Override
protected void doPick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
{
if (ltw.createTransformedShape(getBoundingBox()).intersects(pickArea))
{
retVec.add(getPath(null));
}
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
StyleAttribute styleAttrib = new StyleAttribute();
if (getStyle(styleAttrib.setName("visibility")))
{
if (!styleAttrib.getStringValue().equals("visible"))
{
return;
}
}
if (getStyle(styleAttrib.setName("display")))
{
if (styleAttrib.getStringValue().equals("none"))
{
return;
}
}
beginLayer(g);
float opacity = 1f;
if (getStyle(styleAttrib.setName("opacity")))
{
opacity = styleAttrib.getRatioValue();
}
if (opacity <= 0)
{
return;
}
Composite oldComp = null;
if (opacity < 1)
{
oldComp = g.getComposite();
Composite comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity);
g.setComposite(comp);
}
BufferedImage img = diagram.getUniverse().getImage(imageSrc);
if (img == null)
{
return;
}
AffineTransform curXform = g.getTransform();
g.transform(xform);
g.drawImage(img, 0, 0, diagram.getCurrentRenderTarget());
g.setTransform(curXform);
if (oldComp != null)
{
g.setComposite(oldComp);
}
finishLayer(g);
}
@Override
public Rectangle2D getBoundingBox()
{
return boundsToParent(bounds);
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
boolean changeState = super.updateTime(curTime);
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getPres(sty.setName("x")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != x)
{
x = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("y")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != y)
{
y = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("width")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != width)
{
width = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("height")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != height)
{
height = newVal;
shapeChange = true;
}
}
try
{
if (getPres(sty.setName("xlink:href")))
{
URI src = sty.getURIValue(getXMLBase());
URL newVal = null;
if ("data".equals(src.getScheme()))
{
newVal = new URL(null, src.toASCIIString(), new Handler());
} else if (!diagram.getUniverse().isImageDataInlineOnly())
{
newVal = src.toURL();
}
if (newVal != null && !newVal.equals(imageSrc))
{
imageSrc = newVal;
shapeChange = true;
}
}
} catch (IllegalArgumentException ie)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Image provided with illegal value for href: \""
+ sty.getStringValue() + '"', ie);
} catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse xlink:href", e);
}
if (shapeChange)
{
build();
// diagram.getUniverse().registerImage(imageSrc);
//
// //Set widths if not set
// BufferedImage img = diagram.getUniverse().getImage(imageSrc);
// if (img == null)
// {
// xform = new AffineTransform();
// bounds = new Rectangle2D.Float();
// }
// else
// {
// if (width == 0) width = img.getWidth();
// if (height == 0) height = img.getHeight();
//
// //Determine image xform
// xform = new AffineTransform();
//// xform.setToScale(this.width / img.getWidth(), this.height / img.getHeight());
//// xform.translate(this.x, this.y);
// xform.translate(this.x, this.y);
// xform.scale(this.width / img.getWidth(), this.height / img.getHeight());
//
// bounds = new Rectangle2D.Float(this.x, this.y, this.width, this.height);
// }
//
// return true;
}
return changeState || shapeChange;
}
}

View file

@ -0,0 +1,185 @@
/*
* 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 January 26, 2004, 5:25 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Line extends ShapeElement
{
public static final String TAG_NAME = "line";
float x1 = 0f;
float y1 = 0f;
float x2 = 0f;
float y2 = 0f;
Line2D.Float line;
/**
* Creates a new instance of Rect
*/
public Line()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("x1")))
{
x1 = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("y1")))
{
y1 = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("x2")))
{
x2 = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("y2")))
{
y2 = sty.getFloatValueWithUnits();
}
line = new Line2D.Float(x1, y1, x2, y2);
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
beginLayer(g);
renderShape(g, line);
finishLayer(g);
}
@Override
public Shape getShape()
{
return shapeToParent(line);
}
@Override
public Rectangle2D getBoundingBox() throws SVGException
{
return boundsToParent(includeStrokeInBounds(line.getBounds2D()));
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
boolean changeState = super.updateTime(curTime);
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getPres(sty.setName("x1")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != x1)
{
x1 = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("y1")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != y1)
{
y1 = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("x2")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != x2)
{
x2 = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("y2")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != y2)
{
y2 = newVal;
shapeChange = true;
}
}
if (shapeChange)
{
build();
}
return changeState || shapeChange;
}
}

View file

@ -0,0 +1,225 @@
/*
* 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 January 26, 2004, 1:54 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Color;
import java.awt.LinearGradientPaint;
import java.awt.MultipleGradientPaint;
import java.awt.Paint;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class LinearGradient extends Gradient
{
public static final String TAG_NAME = "lineargradient";
float x1 = 0f;
float y1 = 0f;
float x2 = 1f;
float y2 = 0f;
/**
* Creates a new instance of LinearGradient
*/
public LinearGradient()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("x1")))
{
x1 = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("y1")))
{
y1 = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("x2")))
{
x2 = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("y2")))
{
y2 = sty.getFloatValueWithUnits();
}
}
@Override
public Paint getPaint(Rectangle2D bounds, AffineTransform xform)
{
MultipleGradientPaint.CycleMethod method;
switch (spreadMethod)
{
default:
case SM_PAD:
method = MultipleGradientPaint.CycleMethod.NO_CYCLE;
break;
case SM_REPEAT:
method = MultipleGradientPaint.CycleMethod.REPEAT;
break;
case SM_REFLECT:
method = MultipleGradientPaint.CycleMethod.REFLECT;
break;
}
Paint paint;
Point2D.Float pt1 = new Point2D.Float(x1, y1);
Point2D.Float pt2 = new Point2D.Float(x2, y2);
if (pt1.equals(pt2))
{
Color[] colors = getStopColors();
paint = colors.length > 0 ? colors[0] : Color.black;
} else if (gradientUnits == GU_USER_SPACE_ON_USE)
{
paint = new LinearGradientPaint(
pt1,
pt2,
getStopFractions(),
getStopColors(),
method,
MultipleGradientPaint.ColorSpaceType.SRGB,
gradientTransform == null
? new AffineTransform()
: gradientTransform);
} else
{
AffineTransform viewXform = new AffineTransform();
viewXform.translate(bounds.getX(), bounds.getY());
//This is a hack to get around shapes that have a width or height of 0. Should be close enough to the true answer.
double width = Math.max(1, bounds.getWidth());
double height = Math.max(1, bounds.getHeight());
viewXform.scale(width, height);
if (gradientTransform != null)
{
viewXform.concatenate(gradientTransform);
}
paint = new LinearGradientPaint(
pt1,
pt2,
getStopFractions(),
getStopColors(),
method,
MultipleGradientPaint.ColorSpaceType.SRGB,
viewXform);
}
return paint;
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return stopChange;
boolean changeState = super.updateTime(curTime);
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getPres(sty.setName("x1")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != x1)
{
x1 = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("y1")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != y1)
{
y1 = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("x2")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != x2)
{
x2 = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("y2")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != y2)
{
y2 = newVal;
shapeChange = true;
}
}
return changeState || shapeChange;
}
}

View file

@ -0,0 +1,376 @@
/*
* 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
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
/**
*
* @author kitfox
*/
public class Marker extends Group
{
public static final String TAG_NAME = "marker";
AffineTransform viewXform;
AffineTransform markerXform;
Rectangle2D viewBox;
float refX;
float refY;
float markerWidth = 1;
float markerHeight = 1;
float orient = Float.NaN;
boolean markerUnitsStrokeWidth = true; //if set to false 'userSpaceOnUse' is assumed
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("refX")))
{
refX = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("refY")))
{
refY = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("markerWidth")))
{
markerWidth = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("markerHeight")))
{
markerHeight = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("orient")))
{
if ("auto".equals(sty.getStringValue()))
{
orient = Float.NaN;
} else
{
orient = sty.getFloatValue();
}
}
if (getPres(sty.setName("viewBox")))
{
float[] dim = sty.getFloatList();
viewBox = new Rectangle2D.Float(dim[0], dim[1], dim[2], dim[3]);
}
if (viewBox == null)
{
viewBox = new Rectangle(0, 0, 1, 1);
}
if (getPres(sty.setName("markerUnits")))
{
String markerUnits = sty.getStringValue();
if (markerUnits != null && markerUnits.equals("userSpaceOnUse"))
{
markerUnitsStrokeWidth = false;
}
}
//Transform pattern onto unit square
viewXform = new AffineTransform();
viewXform.scale(1.0 / viewBox.getWidth(), 1.0 / viewBox.getHeight());
viewXform.translate(-viewBox.getX(), -viewBox.getY());
markerXform = new AffineTransform();
markerXform.scale(markerWidth, markerHeight);
markerXform.concatenate(viewXform);
markerXform.translate(-refX, -refY);
}
@Override
protected boolean outsideClip(Graphics2D g) throws SVGException
{
Shape clip = g.getClip();
Rectangle2D rect = super.getBoundingBox();
if (clip == null || clip.intersects(rect))
{
return false;
}
return true;
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
AffineTransform oldXform = g.getTransform();
g.transform(markerXform);
super.doRender(g);
g.setTransform(oldXform);
}
public void render(Graphics2D g, MarkerPos pos, float strokeWidth) throws SVGException
{
AffineTransform cacheXform = g.getTransform();
g.translate(pos.x, pos.y);
if (markerUnitsStrokeWidth)
{
g.scale(strokeWidth, strokeWidth);
}
g.rotate(Math.atan2(pos.dy, pos.dx));
g.transform(markerXform);
super.doRender(g);
g.setTransform(cacheXform);
}
@Override
public Shape getShape()
{
Shape shape = super.getShape();
return markerXform.createTransformedShape(shape);
}
@Override
public Rectangle2D getBoundingBox() throws SVGException
{
Rectangle2D rect = super.getBoundingBox();
return markerXform.createTransformedShape(rect).getBounds2D();
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
boolean changeState = super.updateTime(curTime);
build();
//Marker properties do not change
return changeState;
}
//--------------------------------
public static final int MARKER_START = 0;
public static final int MARKER_MID = 1;
public static final int MARKER_END = 2;
public static class MarkerPos
{
int type;
double x;
double y;
double dx;
double dy;
public MarkerPos(int type, double x, double y, double dx, double dy)
{
this.type = type;
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
}
}
public static class MarkerLayout
{
private ArrayList<MarkerPos> markerList = new ArrayList<MarkerPos>();
boolean started = false;
public void layout(Shape shape)
{
double px = 0;
double py = 0;
double[] coords = new double[6];
for (PathIterator it = shape.getPathIterator(null);
!it.isDone(); it.next())
{
switch (it.currentSegment(coords))
{
case PathIterator.SEG_MOVETO:
px = coords[0];
py = coords[1];
started = false;
break;
case PathIterator.SEG_CLOSE:
started = false;
break;
case PathIterator.SEG_LINETO:
{
double x = coords[0];
double y = coords[1];
markerIn(px, py, x - px, y - py);
markerOut(x, y, x - px, y - py);
px = x;
py = y;
break;
}
case PathIterator.SEG_QUADTO:
{
double k0x = coords[0];
double k0y = coords[1];
double x = coords[2];
double y = coords[3];
//Best in tangent
if (px != k0x || py != k0y)
{
markerIn(px, py, k0x - px, k0y - py);
} else
{
markerIn(px, py, x - px, y - py);
}
//Best out tangent
if (x != k0x || y != k0y)
{
markerOut(x, y, x - k0x, y - k0y);
} else
{
markerOut(x, y, x - px, y - py);
}
markerIn(px, py, k0x - px, k0y - py);
markerOut(x, y, x - k0x, y - k0y);
px = x;
py = y;
break;
}
case PathIterator.SEG_CUBICTO:
{
double k0x = coords[0];
double k0y = coords[1];
double k1x = coords[2];
double k1y = coords[3];
double x = coords[4];
double y = coords[5];
//Best in tangent
if (px != k0x || py != k0y)
{
markerIn(px, py, k0x - px, k0y - py);
} else if (px != k1x || py != k1y)
{
markerIn(px, py, k1x - px, k1y - py);
} else
{
markerIn(px, py, x - px, y - py);
}
//Best out tangent
if (x != k1x || y != k1y)
{
markerOut(x, y, x - k1x, y - k1y);
} else if (x != k0x || y != k0y)
{
markerOut(x, y, x - k0x, y - k0y);
} else
{
markerOut(x, y, x - px, y - py);
}
px = x;
py = y;
break;
}
}
}
for (int i = 1; i < markerList.size(); ++i)
{
MarkerPos prev = (MarkerPos) markerList.get(i - 1);
MarkerPos cur = (MarkerPos) markerList.get(i);
if (cur.type == MARKER_START)
{
prev.type = MARKER_END;
}
}
MarkerPos last = (MarkerPos) markerList.get(markerList.size() - 1);
last.type = MARKER_END;
}
private void markerIn(double x, double y, double dx, double dy)
{
if (started == false)
{
started = true;
markerList.add(new MarkerPos(MARKER_START, x, y, dx, dy));
}
}
private void markerOut(double x, double y, double dx, double dy)
{
markerList.add(new MarkerPos(MARKER_MID, x, y, dx, dy));
}
/**
* @return the markerList
*/
public ArrayList<MarkerPos> getMarkerList()
{
return markerList;
}
}
}

View file

@ -0,0 +1,212 @@
/*
* 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
*/
package org.xbib.graphics.svg;
import java.awt.Color;
import java.awt.Composite;
import java.awt.CompositeContext;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.util.List;
/**
* Implements the mask element.
*
* @author Jannis Weis
*/
public class Mask extends Group
{
public static final String TAG_NAME = "mask";
@Override
public String getTagName() {
return TAG_NAME;
}
@Override
public void render(Graphics2D g)
{
}
public Composite createMaskComposite()
{
return new MaskComposite();
}
@Override
void pick(Point2D point, boolean boundingBox, List<List<SVGElement>> retVec)
{
}
@Override
void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List<List<SVGElement>> retVec)
{
}
public void pickElement(Point2D point, boolean boundingBox,
List<List<SVGElement>> retVec, RenderableElement element) throws SVGException
{
if (boundingBox)
{
element.doPick(point, true, retVec);
} else
{
Rectangle pickPoint = new Rectangle((int) point.getX(), (int) point.getY(), 1, 1);
BufferedImage img = BufferPainter.paintToBuffer(null, new AffineTransform(), pickPoint, this, Color.BLACK);
// Only try picking the element if the picked point is visible.
if (luminanceToAlpha(img.getRGB(0, 0)) > 0)
{
element.doPick(point, false, retVec);
}
}
}
public void pickElement(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox,
List<List<SVGElement>> retVec, RenderableElement element) throws SVGException
{
// If at any point the considered picking area becomes empty we break out early.
if (pickArea.isEmpty()) return;
if (boundingBox)
{
element.doPick(pickArea, ltw,true, retVec);
} else
{
// Clip with the element bounds to avoid creating a larger buffer than needed.
Area transformedBounds = new Area(ltw.createTransformedShape(element.getBoundingBox()));
transformedBounds.intersect(new Area(pickArea));
if (transformedBounds.isEmpty()) return;
Rectangle pickRect = transformedBounds.getBounds();
if (pickRect.isEmpty()) return;
BufferedImage maskArea = BufferPainter.paintToBuffer(null, ltw, pickRect,this, Color.BLACK);
// Pick if any pixel in the pick area is visible.
if (hasVisiblePixel(maskArea))
{
element.doPick(pickArea, ltw, false, retVec);
}
}
}
private boolean hasVisiblePixel(BufferedImage img)
{
Raster raster = img.getRaster();
int x = raster.getMinX();
int w = raster.getWidth();
int y = raster.getMinY();
int h = raster.getHeight();
int[] srcPix = raster.getPixels(x, y, w, h, (int[]) null);
boolean hasVisiblePixel = false;
for (int i = 0; i < srcPix.length; i += 4)
{
int sr = srcPix[i];
int sg = srcPix[i + 1];
int sb = srcPix[i + 2];
if (luminanceToAlpha(sr, sg, sb) > 0)
{
hasVisiblePixel = true;
break;
}
}
return hasVisiblePixel;
}
private static double luminanceToAlpha(int rgb)
{
return luminanceToAlpha((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF);
}
private static double luminanceToAlpha(int r, int g, int b)
{
// Assuming 'linearRGB' as the 'color-interpolation' value of the mask.
return 0.2125 * r + 0.7154 * g + 0.0721 * b;
}
private static class MaskComposite implements Composite, CompositeContext
{
@Override
public CompositeContext createContext(ColorModel srcColorModel,
ColorModel dstColorModel, RenderingHints hints)
{
return this;
}
@Override
public void dispose()
{
}
public void composeRGB(int[] src, int[] dst)
{
int w = src.length;
for (int i = 0; i < w; i += 4)
{
int sr = src[i];
int sg = src[i + 1];
int sb = src[i + 2];
int da = dst[i + 3];
double luminance = luminanceToAlpha(sr, sg, sb) / 255d;
da *= luminance;
dst[i + 3] = Math.min(255, Math.max(0, da));
}
}
@Override
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
assert dstIn == dstOut;
assert src.getNumBands() == dstIn.getNumBands();
int x = dstOut.getMinX();
int w = dstOut.getWidth();
int y = dstOut.getMinY();
int h = dstOut.getHeight();
int[] srcPix = src.getPixels(x, y, w, h, (int[]) null);
int[] dstPix = dstIn.getPixels(x, y, w, h, (int[]) null);
composeRGB(srcPix, dstPix);
dstOut.setPixels(x, y, w, h, dstPix);
}
}
}

View file

@ -0,0 +1,66 @@
/*
* 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 September 19, 2004, 1:56 AM
*/
package org.xbib.graphics.svg;
/**
* Does not hold any information. Included to allow metadata tag to be parsed.
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Metadata extends SVGElement
{
public static final String TAG_NAME = "metadata";
/**
* Creates a new instance of Stop
*/
public Metadata()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
public boolean updateTime(double curTime)
{
return false;
}
}

View file

@ -0,0 +1,291 @@
/*
* 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 February 20, 2004, 10:00 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.pathcmd.BuildHistory;
import org.xbib.graphics.svg.pathcmd.PathCommand;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
/**
* Implements an embedded font.
*
* SVG specification: http://www.w3.org/TR/SVG/fonts.html
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class MissingGlyph extends ShapeElement
{
public static final String TAG_NAME = "missingglyph";
//We may define a path
private Shape path = null;
//Alternately, we may have child graphical elements
private float horizAdvX = -1; //Inherits font's value if not set
private float vertOriginX = -1; //Inherits font's value if not set
private float vertOriginY = -1; //Inherits font's value if not set
private float vertAdvY = -1; //Inherits font's value if not set
/**
* Creates a new instance of Font
*/
public MissingGlyph()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Called after the start element but before the end element to indicate
* each child tag that has been processed
*/
@Override
public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
{
super.loaderAddChild(helper, child);
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
String commandList = "";
if (getPres(sty.setName("d")))
{
commandList = sty.getStringValue();
}
//If glyph path was specified, calculate it
if (commandList != null)
{
String fillRule = getStyle(sty.setName("fill-rule")) ? sty.getStringValue() : "nonzero";
PathCommand[] commands = parsePathList(commandList);
GeneralPath buildPath = new GeneralPath(
fillRule.equals("evenodd") ? GeneralPath.WIND_EVEN_ODD : GeneralPath.WIND_NON_ZERO,
commands.length);
BuildHistory hist = new BuildHistory();
for (int i = 0; i < commands.length; i++)
{
PathCommand cmd = commands[i];
cmd.appendPath(buildPath, hist);
}
//Reflect glyph path to put it in user coordinate system
AffineTransform at = new AffineTransform();
at.scale(1, -1);
path = at.createTransformedShape(buildPath);
}
//Read glyph spacing info
if (getPres(sty.setName("horiz-adv-x")))
{
horizAdvX = sty.getFloatValue();
}
if (getPres(sty.setName("vert-origin-x")))
{
vertOriginX = sty.getFloatValue();
}
if (getPres(sty.setName("vert-origin-y")))
{
vertOriginY = sty.getFloatValue();
}
if (getPres(sty.setName("vert-adv-y")))
{
vertAdvY = sty.getFloatValue();
}
}
public Shape getPath()
{
return path;
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
//Do not push or pop stack
if (path != null)
{
renderShape(g, path);
}
Iterator<SVGElement> it = children.iterator();
while (it.hasNext())
{
SVGElement ele = it.next();
if (ele instanceof RenderableElement)
{
((RenderableElement) ele).render(g);
}
}
//Do not push or pop stack
}
public float getHorizAdvX()
{
if (horizAdvX == -1)
{
horizAdvX = ((Font) parent).getHorizAdvX();
}
return horizAdvX;
}
public float getVertOriginX()
{
if (vertOriginX == -1)
{
vertOriginX = getHorizAdvX() / 2;
}
return vertOriginX;
}
public float getVertOriginY()
{
if (vertOriginY == -1)
{
vertOriginY = ((Font) parent).getFontFace().getAscent();
}
return vertOriginY;
}
public float getVertAdvY()
{
if (vertAdvY == -1)
{
vertAdvY = ((Font) parent).getFontFace().getUnitsPerEm();
}
return vertAdvY;
}
@Override
public Shape getShape()
{
if (path != null)
{
return shapeToParent(path);
}
return null;
}
@Override
public Rectangle2D getBoundingBox() throws SVGException
{
if (path != null)
{
return boundsToParent(includeStrokeInBounds(path.getBounds2D()));
}
return null;
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
//Fonts can't change
return false;
}
/**
* @param path the path to set
*/
public void setPath(Shape path)
{
this.path = path;
}
/**
* @param horizAdvX the horizAdvX to set
*/
public void setHorizAdvX(float horizAdvX)
{
this.horizAdvX = horizAdvX;
}
/**
* @param vertOriginX the vertOriginX to set
*/
public void setVertOriginX(float vertOriginX)
{
this.vertOriginX = vertOriginX;
}
/**
* @param vertOriginY the vertOriginY to set
*/
public void setVertOriginY(float vertOriginY)
{
this.vertOriginY = vertOriginY;
}
/**
* @param vertAdvY the vertAdvY to set
*/
public void setVertAdvY(float vertAdvY)
{
this.vertAdvY = vertAdvY;
}
}

View file

@ -0,0 +1,158 @@
/*
* 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 January 26, 2004, 5:25 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Path extends ShapeElement
{
public static final String TAG_NAME = "path";
// PathCommand[] commands = null;
int fillRule = GeneralPath.WIND_NON_ZERO;
String d = "";
// ExtendedGeneralPath path;
GeneralPath path;
/**
* Creates a new instance of Rect
*/
public Path()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
String fillRuleStrn = (getStyle(sty.setName("fill-rule"))) ? sty.getStringValue() : "nonzero";
fillRule = fillRuleStrn.equals("evenodd") ? GeneralPath.WIND_EVEN_ODD : GeneralPath.WIND_NON_ZERO;
if (getPres(sty.setName("d")))
{
d = sty.getStringValue();
}
path = buildPath(d, fillRule);
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
beginLayer(g);
renderShape(g, path);
finishLayer(g);
}
@Override
public Shape getShape()
{
return shapeToParent(path);
}
@Override
public Rectangle2D getBoundingBox() throws SVGException
{
return boundsToParent(includeStrokeInBounds(path.getBounds2D()));
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
boolean changeState = super.updateTime(curTime);
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getStyle(sty.setName("fill-rule")))
{
int newVal = sty.getStringValue().equals("evenodd")
? GeneralPath.WIND_EVEN_ODD
: GeneralPath.WIND_NON_ZERO;
if (newVal != fillRule)
{
fillRule = newVal;
changeState = true;
}
}
if (getPres(sty.setName("d")))
{
String newVal = sty.getStringValue();
if (!newVal.equals(d))
{
d = newVal;
shapeChange = true;
}
}
if (shapeChange)
{
build();
// path = buildPath(d, fillRule);
// return true;
}
return changeState || shapeChange;
}
}

View file

@ -0,0 +1,285 @@
/*
* 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 January 26, 2004, 3:25 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.pattern.PatternPaint;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.TexturePaint;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class PatternSVG extends FillElement
{
public static final String TAG_NAME = "pattern";
public static final int GU_OBJECT_BOUNDING_BOX = 0;
public static final int GU_USER_SPACE_ON_USE = 1;
int gradientUnits = GU_OBJECT_BOUNDING_BOX;
float x;
float y;
float width;
float height;
AffineTransform patternXform = new AffineTransform();
Rectangle2D.Float viewBox;
Paint texPaint;
/**
* Creates a new instance of Gradient
*/
public PatternSVG()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Called after the start element but before the end element to indicate
* each child tag that has been processed
*/
@Override
public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
{
super.loaderAddChild(helper, child);
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
//Load style string
String href = null;
if (getPres(sty.setName("xlink:href")))
{
href = sty.getStringValue();
}
//String href = attrs.getValue("xlink:href");
//If we have a link to another pattern, initialize ourselves with it's values
if (href != null)
{
//System.err.println("Gradient.loaderStartElement() href '" + href + "'");
try
{
URI src = getXMLBase().resolve(href);
PatternSVG patSrc = (PatternSVG) diagram.getUniverse().getElement(src);
gradientUnits = patSrc.gradientUnits;
x = patSrc.x;
y = patSrc.y;
width = patSrc.width;
height = patSrc.height;
viewBox = patSrc.viewBox;
patternXform.setTransform(patSrc.patternXform);
children.addAll(patSrc.children);
} catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse xlink:href", e);
}
}
String gradientUnits = "";
if (getPres(sty.setName("gradientUnits")))
{
gradientUnits = sty.getStringValue().toLowerCase();
}
if (gradientUnits.equals("userspaceonuse"))
{
this.gradientUnits = GU_USER_SPACE_ON_USE;
} else
{
this.gradientUnits = GU_OBJECT_BOUNDING_BOX;
}
String patternTransform = "";
if (getPres(sty.setName("patternTransform")))
{
patternTransform = sty.getStringValue();
}
patternXform = parseTransform(patternTransform);
if (getPres(sty.setName("x")))
{
x = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("y")))
{
y = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("width")))
{
width = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("height")))
{
height = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("viewBox")))
{
float[] dim = sty.getFloatList();
viewBox = new Rectangle2D.Float(dim[0], dim[1], dim[2], dim[3]);
}
preparePattern();
}
/*
public void loaderEndElement(SVGLoaderHelper helper)
{
build();
}
*/
protected void preparePattern() throws SVGException
{
//For now, treat all fills as UserSpaceOnUse. Otherwise, we'll need
// a different paint for every object.
int tileWidth = (int) width;
int tileHeight = (int) height;
float stretchX = 1f, stretchY = 1f;
if (!patternXform.isIdentity())
{
//Scale our source tile so that we can have nice sampling from it.
float xlateX = (float) patternXform.getTranslateX();
float xlateY = (float) patternXform.getTranslateY();
Point2D.Float pt = new Point2D.Float(), pt2 = new Point2D.Float();
pt.setLocation(width, 0);
patternXform.transform(pt, pt2);
pt2.x -= xlateX;
pt2.y -= xlateY;
stretchX = (float) Math.sqrt(pt2.x * pt2.x + pt2.y * pt2.y) * 1.5f / width;
pt.setLocation(height, 0);
patternXform.transform(pt, pt2);
pt2.x -= xlateX;
pt2.y -= xlateY;
stretchY = (float) Math.sqrt(pt2.x * pt2.x + pt2.y * pt2.y) * 1.5f / height;
tileWidth *= stretchX;
tileHeight *= stretchY;
}
if (tileWidth == 0 || tileHeight == 0)
{
//Use defaults if tile has degenerate size
return;
}
BufferedImage buf = new BufferedImage(tileWidth, tileHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = buf.createGraphics();
g.setClip(0, 0, tileWidth, tileHeight);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (SVGElement ele : children) {
if (ele instanceof RenderableElement)
{
AffineTransform xform = new AffineTransform();
if (viewBox == null)
{
xform.translate(-x, -y);
} else
{
xform.scale(tileWidth / viewBox.width, tileHeight / viewBox.height);
xform.translate(-viewBox.x, -viewBox.y);
}
g.setTransform(xform);
((RenderableElement) ele).render(g);
}
}
g.dispose();
//try {
//javax.imageio.ImageIO.write(buf, "png", new java.io.File("c:\\tmp\\texPaint.png"));
//} catch (Exception e ) {}
if (patternXform.isIdentity())
{
texPaint = new TexturePaint(buf, new Rectangle2D.Float(x, y, width, height));
} else
{
patternXform.scale(1 / stretchX, 1 / stretchY);
texPaint = new PatternPaint(buf, patternXform);
}
}
@Override
public Paint getPaint(Rectangle2D bounds, AffineTransform xform)
{
return texPaint;
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
//Patterns don't change state
return false;
}
}

View file

@ -0,0 +1,170 @@
/*
* 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 January 26, 2004, 5:25 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import org.xbib.graphics.svg.xml.XMLParseUtil;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Polygon extends ShapeElement
{
public static final String TAG_NAME = "polygon";
int fillRule = GeneralPath.WIND_NON_ZERO;
String pointsStrn = "";
GeneralPath path;
/**
* Creates a new instance of Rect
*/
public Polygon()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("points")))
{
pointsStrn = sty.getStringValue();
}
String fillRuleStrn = getStyle(sty.setName("fill-rule")) ? sty.getStringValue() : "nonzero";
fillRule = fillRuleStrn.equals("evenodd") ? GeneralPath.WIND_EVEN_ODD : GeneralPath.WIND_NON_ZERO;
buildPath();
}
protected void buildPath()
{
float[] points = XMLParseUtil.parseFloatList(pointsStrn);
path = new GeneralPath(fillRule, points.length / 2);
path.moveTo(points[0], points[1]);
for (int i = 2; i < points.length; i += 2)
{
path.lineTo(points[i], points[i + 1]);
}
path.closePath();
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
beginLayer(g);
renderShape(g, path);
finishLayer(g);
}
@Override
public Shape getShape()
{
return shapeToParent(path);
}
@Override
public Rectangle2D getBoundingBox() throws SVGException
{
return boundsToParent(includeStrokeInBounds(path.getBounds2D()));
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
boolean changeState = super.updateTime(curTime);
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getStyle(sty.setName("fill-rule")))
{
int newVal = sty.getStringValue().equals("evenodd")
? GeneralPath.WIND_EVEN_ODD
: GeneralPath.WIND_NON_ZERO;
if (newVal != fillRule)
{
fillRule = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("points")))
{
String newVal = sty.getStringValue();
if (!newVal.equals(pointsStrn))
{
pointsStrn = newVal;
shapeChange = true;
}
}
if (shapeChange)
{
build();
// buildPath();
// return true;
}
return changeState || shapeChange;
}
}

View file

@ -0,0 +1,169 @@
/*
* 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 January 26, 2004, 5:25 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import org.xbib.graphics.svg.xml.XMLParseUtil;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Polyline extends ShapeElement
{
public static final String TAG_NAME = "polyline";
int fillRule = GeneralPath.WIND_NON_ZERO;
String pointsStrn = "";
GeneralPath path;
/**
* Creates a new instance of Rect
*/
public Polyline()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
public void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("points")))
{
pointsStrn = sty.getStringValue();
}
String fillRuleStrn = getStyle(sty.setName("fill-rule")) ? sty.getStringValue() : "nonzero";
fillRule = fillRuleStrn.equals("evenodd") ? GeneralPath.WIND_EVEN_ODD : GeneralPath.WIND_NON_ZERO;
buildPath();
}
protected void buildPath()
{
float[] points = XMLParseUtil.parseFloatList(pointsStrn);
path = new GeneralPath(fillRule, points.length / 2);
path.moveTo(points[0], points[1]);
for (int i = 2; i < points.length; i += 2)
{
path.lineTo(points[i], points[i + 1]);
}
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
beginLayer(g);
renderShape(g, path);
finishLayer(g);
}
@Override
public Shape getShape()
{
return shapeToParent(path);
}
@Override
public Rectangle2D getBoundingBox() throws SVGException
{
return boundsToParent(includeStrokeInBounds(path.getBounds2D()));
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
boolean changeState = super.updateTime(curTime);
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getStyle(sty.setName("fill-rule")))
{
int newVal = sty.getStringValue().equals("evenodd")
? GeneralPath.WIND_EVEN_ODD
: GeneralPath.WIND_NON_ZERO;
if (newVal != fillRule)
{
fillRule = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("points")))
{
String newVal = sty.getStringValue();
if (!newVal.equals(pointsStrn))
{
pointsStrn = newVal;
shapeChange = true;
}
}
if (shapeChange)
{
build();
// buildPath();
// return true;
}
return changeState || shapeChange;
}
}

View file

@ -0,0 +1,242 @@
/*
* 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 January 26, 2004, 1:55 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Color;
import java.awt.MultipleGradientPaint;
import java.awt.Paint;
import java.awt.RadialGradientPaint;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class RadialGradient extends Gradient
{
public static final String TAG_NAME = "radialgradient";
float cx = 0.5f;
float cy = 0.5f;
boolean hasFocus = false;
float fx = 0f;
float fy = 0f;
float r = 0.5f;
/**
* Creates a new instance of RadialGradient
*/
public RadialGradient()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("cx")))
{
cx = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("cy")))
{
cy = sty.getFloatValueWithUnits();
}
hasFocus = false;
if (getPres(sty.setName("fx")))
{
fx = sty.getFloatValueWithUnits();
hasFocus = true;
}
if (getPres(sty.setName("fy")))
{
fy = sty.getFloatValueWithUnits();
hasFocus = true;
}
if (getPres(sty.setName("r")))
{
r = sty.getFloatValueWithUnits();
}
}
@Override
public Paint getPaint(Rectangle2D bounds, AffineTransform xform)
{
MultipleGradientPaint.CycleMethod method;
switch (spreadMethod)
{
default:
case SM_PAD:
method = MultipleGradientPaint.CycleMethod.NO_CYCLE;
break;
case SM_REPEAT:
method = MultipleGradientPaint.CycleMethod.REPEAT;
break;
case SM_REFLECT:
method = MultipleGradientPaint.CycleMethod.REFLECT;
break;
}
Paint paint;
Point2D.Float pt1 = new Point2D.Float(cx, cy);
Point2D.Float pt2 = hasFocus ? new Point2D.Float(fx, fy) : pt1;
float[] stopFractions = getStopFractions();
Color[] stopColors = getStopColors();
//Verify that the stop fractions are valid
{
//for (int i = 0; i <
}
if (gradientUnits == GU_USER_SPACE_ON_USE)
{
paint = new RadialGradientPaint(
pt1,
r,
pt2,
stopFractions,
stopColors,
method,
MultipleGradientPaint.ColorSpaceType.SRGB,
gradientTransform);
} else
{
AffineTransform viewXform = new AffineTransform();
viewXform.translate(bounds.getX(), bounds.getY());
viewXform.scale(bounds.getWidth(), bounds.getHeight());
viewXform.concatenate(gradientTransform);
paint = new RadialGradientPaint(
pt1,
r,
pt2,
stopFractions,
stopColors,
method,
MultipleGradientPaint.ColorSpaceType.SRGB,
viewXform);
}
return paint;
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
boolean changeState = super.updateTime(curTime);
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getPres(sty.setName("cx")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != cx)
{
cx = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("cy")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != cy)
{
cy = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("fx")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != fx)
{
fx = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("fy")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != fy)
{
fy = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("r")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != r)
{
r = newVal;
shapeChange = true;
}
}
return changeState;
}
}

View file

@ -0,0 +1,317 @@
/*
* 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 January 26, 2004, 5:25 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RectangularShape;
import java.awt.geom.RoundRectangle2D;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Rect extends ShapeElement
{
public static final String TAG_NAME = "rect";
float x = 0f;
float y = 0f;
float width = 0f;
float height = 0f;
float rx = 0f;
float ry = 0f;
RectangularShape rect;
/**
* Creates a new instance of Rect
*/
public Rect()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
private void writeObject(ObjectOutputStream out) throws IOException
{
out.writeFloat(x);
out.writeFloat(y);
out.writeFloat(width);
out.writeFloat(height);
out.writeFloat(rx);
out.writeFloat(ry);
}
private void readObject(ObjectInputStream in) throws IOException
{
x = in.readFloat();
y = in.readFloat();
width = in.readFloat();
height = in.readFloat();
rx = in.readFloat();
ry = in.readFloat();
if (rx == 0f && ry == 0f)
{
rect = new Rectangle2D.Float(x, y, width, height);
} else
{
rect = new RoundRectangle2D.Float(x, y, width, height, rx * 2, ry * 2);
}
}
/*
public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent)
{
//Load style string
super.loaderStartElement(helper, attrs, parent);
String x = attrs.getValue("x");
String y = attrs.getValue("y");
String width = attrs.getValue("width");
String height = attrs.getValue("height");
String rx = attrs.getValue("rx");
String ry = attrs.getValue("ry");
if (rx == null) rx = ry;
if (ry == null) ry = rx;
this.x = XMLParseUtil.parseFloat(x);
this.y = XMLParseUtil.parseFloat(y);
this.width = XMLParseUtil.parseFloat(width);
this.height = XMLParseUtil.parseFloat(height);
if (rx != null)
{
this.rx = XMLParseUtil.parseFloat(rx);
this.ry = XMLParseUtil.parseFloat(ry);
}
build();
// setBounds(this.x, this.y, this.width, this.height);
}
*/
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
// SVGElement parent = this.getParent();
// if (parent instanceof RenderableElement)
// {
// RenderableElement re = (RenderableElement)parent;
// Rectangle2D bounds = re.getBoundingBox();
// bounds = null;
// }
if (getPres(sty.setName("x")))
{
x = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("y")))
{
y = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("width")))
{
width = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("height")))
{
height = sty.getFloatValueWithUnits();
}
boolean rxSet = false;
if (getPres(sty.setName("rx")))
{
rx = sty.getFloatValueWithUnits();
rxSet = true;
}
boolean rySet = false;
if (getPres(sty.setName("ry")))
{
ry = sty.getFloatValueWithUnits();
rySet = true;
}
if (!rxSet)
{
rx = ry;
}
if (!rySet)
{
ry = rx;
}
if (rx == 0f && ry == 0f)
{
rect = new Rectangle2D.Float(x, y, width, height);
} else
{
rect = new RoundRectangle2D.Float(x, y, width, height, rx * 2, ry * 2);
}
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
beginLayer(g);
renderShape(g, rect);
finishLayer(g);
}
@Override
public Shape getShape()
{
return shapeToParent(rect);
}
@Override
public Rectangle2D getBoundingBox() throws SVGException
{
return boundsToParent(includeStrokeInBounds(rect.getBounds2D()));
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
boolean changeState = super.updateTime(curTime);
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getPres(sty.setName("x")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != x)
{
x = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("y")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != y)
{
y = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("width")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != width)
{
width = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("height")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != height)
{
height = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("rx")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != rx)
{
rx = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("ry")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != ry)
{
ry = newVal;
shapeChange = true;
}
}
if (shapeChange)
{
build();
// if (rx == 0f && ry == 0f)
// {
// rect = new Rectangle2D.Float(x, y, width, height);
// }
// else
// {
// rect = new RoundRectangle2D.Float(x, y, width, height, rx * 2, ry * 2);
// }
// return true;
}
return changeState || shapeChange;
}
}

View file

@ -0,0 +1,255 @@
/*
* 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 January 26, 2004, 9:00 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.net.URI;
import java.util.List;
/**
* Maintains bounding box for this element
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
abstract public class RenderableElement extends TransformableElement
{
AffineTransform cachedXform = null;
Mask cachedMask;
Filter filter;
Shape cachedClip = null;
public static final int VECTOR_EFFECT_NONE = 0;
public static final int VECTOR_EFFECT_NON_SCALING_STROKE = 1;
int vectorEffect;
private BufferPainter.Cache bufferCache;
/**
* Creates a new instance of BoundedElement
*/
public RenderableElement()
{
}
public RenderableElement(String id, SVGElement parent)
{
super(id, parent);
}
BufferPainter.Cache getBufferCache()
{
return bufferCache;
}
void setBufferImage(BufferPainter.Cache bufferCache)
{
this.bufferCache = bufferCache;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("vector-effect")))
{
if ("non-scaling-stroke".equals(sty.getStringValue()))
{
vectorEffect = VECTOR_EFFECT_NON_SCALING_STROKE;
} else
{
vectorEffect = VECTOR_EFFECT_NONE;
}
} else
{
vectorEffect = VECTOR_EFFECT_NONE;
}
cachedMask = getMask(sty);
filter = getFilter(sty);
}
public void render(Graphics2D g) throws SVGException
{
BufferPainter.paintElement(g, this);
}
private Mask getMask(StyleAttribute styleAttrib) throws SVGException
{
if (getStyle(styleAttrib.setName("mask"), false)
&& !"none".equals(styleAttrib.getStringValue())) {
URI uri = styleAttrib.getURIValue(getXMLBase());
if (uri == null) {
return null;
}
return (Mask) diagram.getUniverse().getElement(uri);
}
return null;
}
private Filter getFilter(StyleAttribute styleAttrib) throws SVGException
{
if (getStyle(styleAttrib.setName("filter"), false)
&& !"none".equals(styleAttrib.getStringValue())) {
URI uri = styleAttrib.getURIValue(getXMLBase());
if (uri == null) {
return null;
}
return (Filter) diagram.getUniverse().getElement(uri);
}
return null;
}
abstract protected void doRender(Graphics2D g) throws SVGException;
void pick(Point2D point, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
{
if (cachedMask != null)
{
cachedMask.pickElement(point, boundingBox, retVec, this);
} else
{
doPick(point, boundingBox, retVec);
}
}
protected abstract void doPick(Point2D point, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException;
void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
{
if (cachedMask != null)
{
cachedMask.pickElement(pickArea, ltw, boundingBox, retVec, this);
} else
{
doPick(pickArea, ltw, boundingBox, retVec);
}
}
protected abstract void doPick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException;
abstract public Rectangle2D getBoundingBox() throws SVGException;
/*
public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent)
{
super.loaderStartElement(helper, attrs, parent);
}
*/
/**
* Pushes transform stack, transforms to local coordinates and sets up
* clipping mask.
*
* @param g Graphics context
* @throws SVGException
*/
protected void beginLayer(Graphics2D g) throws SVGException
{
if (xform != null)
{
cachedXform = g.getTransform();
g.transform(xform);
}
StyleAttribute styleAttrib = new StyleAttribute();
//Get clipping path
// StyleAttribute styleAttrib = getStyle("clip-path", false);
Shape clipPath = null;
int clipPathUnits = ClipPath.CP_USER_SPACE_ON_USE;
if (getStyle(styleAttrib.setName("clip-path"), false)
&& !"none".equals(styleAttrib.getStringValue()))
{
URI uri = styleAttrib.getURIValue(getXMLBase());
if (uri != null)
{
ClipPath ele = (ClipPath) diagram.getUniverse().getElement(uri);
clipPath = ele.getClipPathShape();
clipPathUnits = ele.getClipPathUnits();
}
}
//Return if we're out of clipping range
if (clipPath != null)
{
if (clipPathUnits == ClipPath.CP_OBJECT_BOUNDING_BOX && (this instanceof ShapeElement))
{
Rectangle2D rect = ((ShapeElement) this).getBoundingBox();
AffineTransform at = new AffineTransform();
at.scale(rect.getWidth(), rect.getHeight());
clipPath = at.createTransformedShape(clipPath);
}
cachedClip = g.getClip();
if (cachedClip == null)
{
g.setClip(clipPath);
} else
{
Area newClip = new Area(cachedClip);
newClip.intersect(new Area(clipPath));
g.setClip(newClip);
}
}
}
/**
* Restores transform and clipping values to the way they were before this
* layer was drawn.
* @param g
*/
protected void finishLayer(Graphics2D g)
{
if (cachedClip != null)
{
g.setClip(cachedClip);
}
if (cachedXform != null)
{
g.setTransform(cachedXform);
}
}
}

View file

@ -0,0 +1,58 @@
/*
* 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 2, 2005, 1:54 AM
*/
package org.xbib.graphics.svg;
/**
* A convienience singleton for allowing all classes to access a common SVG universe.
*
* @author kitfox
*/
public class SVGCache
{
private static final SVGUniverse svgUniverse = new SVGUniverse();
/** Creates a new instance of SVGUniverseSingleton */
private SVGCache()
{
}
public static SVGUniverse getSVGUniverse()
{
return svgUniverse;
}
}

View file

@ -0,0 +1,14 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.xbib.graphics.svg;
/**
*
* @author kitfox
*/
public interface SVGConst
{
public static final String SVG_LOGGER = "svgSalamandeLogger";
}

View file

@ -0,0 +1,286 @@
/*
* 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 February 18, 2004, 5:04 PM
*/
package org.xbib.graphics.svg;
import javax.swing.JComponent;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Top level structure in an SVG tree.
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class SVGDiagram implements Serializable
{
public static final long serialVersionUID = 0;
//Indexes elements within this SVG diagram
final HashMap<String, SVGElement> idMap = new HashMap<String, SVGElement>();
SVGRoot root;
final SVGUniverse universe;
private JComponent renderTarget;
/**
* This is used by the SVGRoot to determine the width of the
*/
private Rectangle deviceViewport = new Rectangle(100, 100);
/**
* If true, no attempt will be made to discard geometry based on it being
* out of bounds. This trades potentially drawing many out of bounds
* shapes with having to recalculate bounding boxes every animation iteration.
*/
protected boolean ignoreClipHeuristic = false;
/**
* URL which uniquely identifies this document
*/
// final URI docRoot;
/**
* URI that uniquely identifies this document. Also used to resolve
* relative urls. Default base for document.
*/
final URI xmlBase;
/**
* Creates a new instance of SVGDiagram
* @param xmlBase
* @param universe
*/
public SVGDiagram(URI xmlBase, SVGUniverse universe)
{
this.universe = universe;
// this.docRoot = docRoot;
this.xmlBase = xmlBase;
}
JComponent getCurrentRenderTarget()
{
return renderTarget;
}
public void render(JComponent c, Graphics2D g) throws SVGException
{
renderTarget = c;
root.renderToViewport(g);
renderTarget = null;
}
/**
* Draws this diagram to the passed graphics context
* @param g
* @throws SVGException
*/
public void render(Graphics2D g) throws SVGException
{
render(null, g);
}
/**
* Searches thorough the scene graph for all RenderableElements that have
* shapes that contain the passed point.
*
* For every shape which contains the pick point, a List containing the
* path to the node is added to the return list. That is, the result of
* SVGElement.getPath() is added for each entry.
*
* @param point
* @param retVec
* @return the passed in list
* @throws SVGException
*/
public List<List<SVGElement>> pick(Point2D point, List<List<SVGElement>> retVec) throws SVGException
{
return pick(point, false, retVec);
}
public List<List<SVGElement>> pick(Point2D point, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
{
if (retVec == null)
{
retVec = new ArrayList<List<SVGElement>>();
}
root.pick(point, boundingBox, retVec);
return retVec;
}
public List<List<SVGElement>> pick(Rectangle2D pickArea, List<List<SVGElement>> retVec) throws SVGException
{
return pick(pickArea, false, retVec);
}
public List<List<SVGElement>> pick(Rectangle2D pickArea, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
{
if (retVec == null)
{
retVec = new ArrayList<List<SVGElement>>();
}
root.pick(pickArea, new AffineTransform(), boundingBox, retVec);
return retVec;
}
public SVGUniverse getUniverse()
{
return universe;
}
public URI getXMLBase()
{
return xmlBase;
}
// public URL getDocRoot()
// {
// return docRoot;
// }
public float getWidth()
{
if (root == null) return 0;
return root.getDeviceWidth();
}
public float getHeight()
{
if (root == null) return 0;
return root.getDeviceHeight();
}
/**
* Returns the viewing rectangle of this diagram in device coordinates.
* @param rect
* @return
*/
public Rectangle2D getViewRect(Rectangle2D rect)
{
if (root != null) return root.getDeviceRect(rect);
return rect;
}
public Rectangle2D getViewRect()
{
return getViewRect(new Rectangle2D.Double());
}
public SVGElement getElement(String name)
{
return (SVGElement)idMap.get(name);
}
public void setElement(String name, SVGElement node)
{
idMap.put(name, node);
}
public void removeElement(String name)
{
idMap.remove(name);
}
public SVGRoot getRoot()
{
return root;
}
public void setRoot(SVGRoot root)
{
this.root = root;
root.setDiagram(this);
}
public boolean ignoringClipHeuristic() { return ignoreClipHeuristic; }
public void setIgnoringClipHeuristic(boolean ignoreClipHeuristic) { this.ignoreClipHeuristic = ignoreClipHeuristic; }
/**
* Updates all attributes in this diagram associated with a time event.
* Ie, all attributes with track information.
* @param curTime
* @throws SVGException
*/
public void updateTime(double curTime) throws SVGException
{
if (root == null) return;
root.updateTime(curTime);
}
public Rectangle getDeviceViewport()
{
return deviceViewport;
}
/**
* Sets the dimensions of the device being rendered into. This is used by
* SVGRoot when its x, y, width or height parameters are specified as
* percentages.
* @param deviceViewport
*/
public void setDeviceViewport(Rectangle deviceViewport)
{
this.deviceViewport.setBounds(deviceViewport);
if (root != null)
{
try
{
root.build();
} catch (SVGException ex)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not build document", ex);
}
}
}
}

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.2" maxVersion="1.2" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Events>
<EventHandler event="componentResized" listener="java.awt.event.ComponentListener" parameters="java.awt.event.ComponentEvent" handler="formComponentResized"/>
</Events>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
</Form>

View file

@ -0,0 +1,211 @@
/*
* 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 February 20, 2004, 12:29 PM
*/
package org.xbib.graphics.svg;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class SVGDisplayPanel extends javax.swing.JPanel implements Scrollable
{
public static final long serialVersionUID = 1;
SVGDiagram diagram = null;
float scale = 1f;
Color bgColor = null;
/** Creates new form SVGDisplayPanel */
public SVGDisplayPanel()
{
initComponents();
}
public SVGDiagram getDiagram()
{
return diagram;
}
public void setDiagram(SVGDiagram diagram)
{
this.diagram = diagram;
diagram.setDeviceViewport(getBounds());
setDimension();
}
public void setScale(float scale)
{
this.scale = scale;
setDimension();
}
public void setBgColor(Color col)
{
bgColor = col;
}
private void setDimension()
{
if (diagram == null)
{
setPreferredSize(new Dimension(1, 1));
revalidate();
return;
}
final Rectangle2D.Float rect = new Rectangle2D.Float();
diagram.getViewRect(rect);
int w = (int)(rect.width * scale);
int h = (int)(rect.height * scale);
setPreferredSize(new Dimension(w, h));
revalidate();
}
/**
* Update this image to reflect the passed time
* @param curTime
* @throws SVGException
*/
public void updateTime(double curTime) throws SVGException
{
if (diagram == null) return;
diagram.updateTime(curTime);
}
@Override
public void paintComponent(Graphics gg)
{
Graphics2D g = (Graphics2D)gg;
if (bgColor != null)
{
Dimension dim = getSize();
g.setColor(bgColor);
g.fillRect(0, 0, dim.width, dim.height);
}
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
if (diagram != null)
{
try
{
diagram.render(g);
}
catch (SVGException e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not render diagram", e);
}
}
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
private void initComponents()
{
setLayout(new java.awt.BorderLayout());
addComponentListener(new java.awt.event.ComponentAdapter()
{
@Override
public void componentResized(java.awt.event.ComponentEvent evt)
{
formComponentResized(evt);
}
});
}// </editor-fold>//GEN-END:initComponents
private void formComponentResized(java.awt.event.ComponentEvent evt)//GEN-FIRST:event_formComponentResized
{//GEN-HEADEREND:event_formComponentResized
if (diagram != null)
{
diagram.setDeviceViewport(getBounds());
setDimension();
}
}//GEN-LAST:event_formComponentResized
public Dimension getPreferredScrollableViewportSize()
{
return getPreferredSize();
}
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
{
if (orientation == SwingConstants.HORIZONTAL)
{
return visibleRect.width;
}
else return visibleRect.height;
}
public boolean getScrollableTracksViewportHeight()
{
return false;
}
public boolean getScrollableTracksViewportWidth()
{
return false;
}
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
{
return getScrollableBlockIncrement(visibleRect, orientation, direction) / 16;
}
// Variables declaration - do not modify//GEN-BEGIN:variables
// End of variables declaration//GEN-END:variables
}

View file

@ -0,0 +1,863 @@
/*
* 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 January 26, 2004, 1:59 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.animation.AnimationElement;
import org.xbib.graphics.svg.animation.TrackBase;
import org.xbib.graphics.svg.animation.TrackManager;
import org.xbib.graphics.svg.pathcmd.BuildHistory;
import org.xbib.graphics.svg.pathcmd.PathCommand;
import org.xbib.graphics.svg.pathcmd.PathParser;
import org.xbib.graphics.svg.xml.StyleAttribute;
import org.xbib.graphics.svg.xml.StyleSheet;
import org.xbib.graphics.svg.xml.XMLParseUtil;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.io.Serializable;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
abstract public class SVGElement implements Serializable
{
public static final long serialVersionUID = 0;
public static final String SVG_NS = "http://www.w3.org/2000/svg";
protected SVGElement parent = null;
protected final ArrayList<SVGElement> children = new ArrayList<SVGElement>();
protected String id = null;
/**
* CSS class. Used for applying style sheet information.
*/
protected String cssClass = null;
/**
* Styles defined for this elemnt via the <b>style</b> attribute.
*/
protected final HashMap<String, StyleAttribute> inlineStyles = new HashMap<String, StyleAttribute>();
/**
* Presentation attributes set for this element. Ie, any attribute other
* than the <b>style</b> attribute.
*/
protected final HashMap<String, StyleAttribute> presAttribs = new HashMap<String, StyleAttribute>();
/**
* This element may override the URI we resolve against with an xml:base
* attribute. If so, a copy is placed here. Otherwise, we defer to our
* parent for the reolution base
*/
protected URI xmlBase = null;
/**
* The diagram this element belongs to
*/
protected SVGDiagram diagram;
/**
* Link to the universe we reside in
*/
protected final TrackManager trackManager = new TrackManager();
boolean dirty = true;
/**
* Creates a new instance of SVGElement
*/
public SVGElement()
{
this(null, null, null);
}
public SVGElement(String id, SVGElement parent)
{
this(id, null, parent);
}
public SVGElement(String id, String cssClass, SVGElement parent)
{
this.id = id;
this.cssClass = cssClass;
this.parent = parent;
}
abstract public String getTagName();
public SVGElement getParent()
{
return parent;
}
void setParent(SVGElement parent)
{
this.parent = parent;
}
/**
* @param retVec
* @return an ordered list of nodes from the root of the tree to this node
*/
public List<SVGElement> getPath(List<SVGElement> retVec)
{
if (retVec == null)
{
retVec = new ArrayList<SVGElement>();
}
if (parent != null)
{
parent.getPath(retVec);
}
retVec.add(this);
return retVec;
}
/**
* @param retVec - A list to add all children to. If null, a new list is
* created and children of this group are added.
*
* @return The list containing the children of this group
*/
public List<SVGElement> getChildren(List<SVGElement> retVec)
{
if (retVec == null)
{
retVec = new ArrayList<SVGElement>();
}
retVec.addAll(children);
return retVec;
}
/**
* @param id - Id of svg element to return
* @return the child of the given id, or null if no such child exists.
*/
public SVGElement getChild(String id)
{
for (SVGElement ele : children) {
String eleId = ele.getId();
if (eleId != null && eleId.equals(id))
{
return ele;
}
}
return null;
}
/**
* Searches children for given element. If found, returns index of child.
* Otherwise returns -1.
* @param child
* @return index of child
*/
public int indexOfChild(SVGElement child)
{
return children.indexOf(child);
}
/**
* Swaps 2 elements in children.
*
* @param i index of first child
* @param j index of second child
* @throws SVGException
*/
public void swapChildren(int i, int j) throws SVGException
{
if ((children == null) || (i < 0) || (i >= children.size()) || (j < 0) || (j >= children.size()))
{
return;
}
SVGElement temp = children.get(i);
children.set(i, children.get(j));
children.set(j, temp);
build();
}
/**
* Called during SAX load process to notify that this tag has begun the
* process of being loaded
*
* @param attrs - Attributes of this tag
* @param helper - An object passed to all SVG elements involved in this
* build process to aid in sharing information.
* @param parent
* @throws org.xml.sax.SAXException
*/
public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) throws SAXException
{
//Set identification info
this.parent = parent;
this.diagram = helper.diagram;
this.id = attrs.getValue("id");
if (this.id != null && !this.id.equals(""))
{
this.id = this.id.intern();
diagram.setElement(this.id, this);
}
String className = attrs.getValue("class");
this.cssClass = (className == null || className.equals("")) ? null : className.intern();
//docRoot = helper.docRoot;
//universe = helper.universe;
//Parse style string, if any
String style = attrs.getValue("style");
if (style != null)
{
HashMap<?, ?> map = XMLParseUtil.parseStyle(style, inlineStyles);
}
String base = attrs.getValue("xml:base");
if (base != null && !base.equals(""))
{
try
{
xmlBase = new URI(base);
} catch (Exception e)
{
throw new SAXException(e);
}
}
//Place all other attributes into the presentation attribute list
int numAttrs = attrs.getLength();
for (int i = 0; i < numAttrs; i++)
{
String name = attrs.getQName(i).intern();
String value = attrs.getValue(i);
presAttribs.put(name, new StyleAttribute(name, value == null ? null : value.intern()));
}
}
public void removeAttribute(String name, int attribType)
{
switch (attribType)
{
case AnimationElement.AT_CSS:
inlineStyles.remove(name);
return;
case AnimationElement.AT_XML:
presAttribs.remove(name);
return;
}
}
public void addAttribute(String name, int attribType, String value) throws SVGElementException
{
if (hasAttribute(name, attribType))
{
throw new SVGElementException(this, "Attribute " + name + "(" + AnimationElement.animationElementToString(attribType) + ") already exists");
}
//Alter layout for id attribute
if ("id".equals(name))
{
if (diagram != null)
{
diagram.removeElement(id);
diagram.setElement(value, this);
}
this.id = value;
}
switch (attribType)
{
case AnimationElement.AT_CSS:
inlineStyles.put(name, new StyleAttribute(name, value));
return;
case AnimationElement.AT_XML:
presAttribs.put(name, new StyleAttribute(name, value));
return;
}
throw new SVGElementException(this, "Invalid attribute type " + attribType);
}
public boolean hasAttribute(String name, int attribType) throws SVGElementException
{
switch (attribType)
{
case AnimationElement.AT_CSS:
return inlineStyles.containsKey(name);
case AnimationElement.AT_XML:
return presAttribs.containsKey(name);
case AnimationElement.AT_AUTO:
return inlineStyles.containsKey(name) || presAttribs.containsKey(name);
}
throw new SVGElementException(this, "Invalid attribute type " + attribType);
}
/**
* @return a set of Strings that correspond to CSS attributes on this element
*/
public Set<String> getInlineAttributes()
{
return inlineStyles.keySet();
}
/**
* @return a set of Strings that correspond to XML attributes on this element
*/
public Set<String> getPresentationAttributes()
{
return presAttribs.keySet();
}
/**
* Called after the start element but before the end element to indicate
* each child tag that has been processed
* @param helper
* @param child
* @throws SVGElementException
*/
public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
{
children.add(child);
child.parent = this;
child.setDiagram(diagram);
//Add info to track if we've scanned animation element
if (child instanceof AnimationElement)
{
trackManager.addTrackElement((AnimationElement) child);
}
}
protected void setDiagram(SVGDiagram diagram)
{
this.diagram = diagram;
diagram.setElement(id, this);
for (SVGElement ele : children) {
ele.setDiagram(diagram);
}
}
public void removeChild(SVGElement child) throws SVGElementException
{
if (!children.contains(child))
{
throw new SVGElementException(this, "Element does not contain child " + child);
}
children.remove(child);
}
/**
* Called during load process to add text scanned within a tag
* @param helper
* @param text
*/
public void loaderAddText(SVGLoaderHelper helper, String text)
{
}
/**
* Called to indicate that this tag and the tags it contains have been
* completely processed, and that it should finish any load processes.
* @param helper
* @throws SVGParseException
*/
public void loaderEndElement(SVGLoaderHelper helper) throws SVGParseException
{
// try
// {
// build();
// }
// catch (SVGException se)
// {
// throw new SVGParseException(se);
// }
}
/**
* Called by internal processes to rebuild the geometry of this node from
* it's presentation attributes, style attributes and animated tracks.
* @throws SVGException
*/
protected void build() throws SVGException
{
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("id")))
{
String newId = sty.getStringValue();
if (!newId.equals(id))
{
diagram.removeElement(id);
id = newId;
diagram.setElement(this.id, this);
}
}
if (getPres(sty.setName("class")))
{
cssClass = sty.getStringValue();
}
if (getPres(sty.setName("xml:base")))
{
xmlBase = sty.getURIValue();
}
//Build children
for (int i = 0; i < children.size(); ++i)
{
SVGElement ele = (SVGElement) children.get(i);
ele.build();
}
}
public URI getXMLBase()
{
return xmlBase != null ? xmlBase
: (parent != null ? parent.getXMLBase() : diagram.getXMLBase());
}
/**
* @return the id assigned to this node. Null if no id explicitly set.
*/
public String getId()
{
return id;
}
LinkedList<SVGElement> contexts = new LinkedList<SVGElement>();
/**
* Hack to allow nodes to temporarily change their parents. The Use tag will
* need this so it can alter the attributes that a particular node uses.
* @param context
*/
protected void pushParentContext(SVGElement context)
{
contexts.addLast(context);
}
protected SVGElement popParentContext()
{
return (SVGElement) contexts.removeLast();
}
protected SVGElement getParentContext()
{
return contexts.isEmpty() ? null : (SVGElement) contexts.getLast();
}
public SVGRoot getRoot()
{
return parent == null ? null : parent.getRoot();
}
/*
* Returns the named style attribute. Checks for inline styles first, then
* internal and extranal style sheets, and finally checks for presentation
* attributes.
* @param styleName - Name of attribute to return
* @param recursive - If true and this object does not contain the
* named style attribute, checks attributes of parents abck to root until
* one found.
*/
public boolean getStyle(StyleAttribute attrib) throws SVGException
{
return getStyle(attrib, true);
}
public void setAttribute(String name, int attribType, String value) throws SVGElementException
{
StyleAttribute styAttr;
switch (attribType)
{
case AnimationElement.AT_CSS:
{
styAttr = (StyleAttribute) inlineStyles.get(name);
break;
}
case AnimationElement.AT_XML:
{
styAttr = (StyleAttribute) presAttribs.get(name);
break;
}
case AnimationElement.AT_AUTO:
{
styAttr = (StyleAttribute) inlineStyles.get(name);
if (styAttr == null)
{
styAttr = (StyleAttribute) presAttribs.get(name);
}
break;
}
default:
throw new SVGElementException(this, "Invalid attribute type " + attribType);
}
if (styAttr == null)
{
throw new SVGElementException(this, "Could not find attribute " + name + "(" + AnimationElement.animationElementToString(attribType) + "). Make sure to create attribute before setting it.");
}
//Alter layout for relevant attributes
if ("id".equals(styAttr.getName()))
{
if (diagram != null)
{
diagram.removeElement(this.id);
diagram.setElement(value, this);
}
this.id = value;
}
styAttr.setStringValue(value);
}
public boolean getStyle(StyleAttribute attrib, boolean recursive) throws SVGException
{
return getStyle(attrib, recursive, true);
}
/**
* Copies the current style into the passed style attribute. Checks for
* inline styles first, then internal and extranal style sheets, and finally
* checks for presentation attributes. Recursively checks parents.
*
* @param attrib - Attribute to write style data to. Must have it's name set
* to the name of the style being queried.
* @param recursive - If true and this object does not contain the named
* style attribute, checks attributes of parents back to root until one
* found.
* @param evalAnimation
* @return
*/
public boolean getStyle(StyleAttribute attrib, boolean recursive, boolean evalAnimation)
throws SVGException
{
String styName = attrib.getName();
//Check for local inline styles
StyleAttribute styAttr = (StyleAttribute)inlineStyles.get(styName);
attrib.setStringValue(styAttr == null ? "" : styAttr.getStringValue());
//Evalutate corresponding track, if one exists
if (evalAnimation)
{
TrackBase track = trackManager.getTrack(styName, AnimationElement.AT_CSS);
if (track != null)
{
track.getValue(attrib, diagram.getUniverse().getCurTime());
return true;
}
}
//Return if we've found a non animated style
if (styAttr != null)
{
return true;
}
//Check for presentation attribute
StyleAttribute presAttr = (StyleAttribute)presAttribs.get(styName);
attrib.setStringValue(presAttr == null ? "" : presAttr.getStringValue());
//Evalutate corresponding track, if one exists
if (evalAnimation)
{
TrackBase track = trackManager.getTrack(styName, AnimationElement.AT_XML);
if (track != null)
{
track.getValue(attrib, diagram.getUniverse().getCurTime());
return true;
}
}
//Return if we've found a presentation attribute instead
if (presAttr != null)
{
return true;
}
//Check for style sheet
SVGRoot root = getRoot();
if (root != null)
{
StyleSheet ss = root.getStyleSheet();
if (ss != null)
{
return ss.getStyle(attrib, getTagName(), cssClass);
}
}
//If we're recursive, check parents
if (recursive)
{
SVGElement parentContext = getParentContext();
if (parentContext != null)
{
return parentContext.getStyle(attrib, true);
}
if (parent != null)
{
return parent.getStyle(attrib, true);
}
}
//Unsuccessful reading style attribute
return false;
}
/**
* @param styName
* @return the raw style value of this attribute. Does not take the
* presentation value or animation into consideration. Used by animations to
* determine the base to animate from.
*/
public StyleAttribute getStyleAbsolute(String styName)
{
//Check for local inline styles
return (StyleAttribute) inlineStyles.get(styName);
}
/**
* Copies the presentation attribute into the passed one.
*
* @param attrib
* @return - True if attribute was read successfully
* @throws SVGException
*/
public boolean getPres(StyleAttribute attrib) throws SVGException
{
String presName = attrib.getName();
//Make sure we have a corresponding presentation attribute
StyleAttribute presAttr = (StyleAttribute) presAttribs.get(presName);
//Copy presentation value directly
attrib.setStringValue(presAttr == null ? "" : presAttr.getStringValue());
//Evalutate corresponding track, if one exists
TrackBase track = trackManager.getTrack(presName, AnimationElement.AT_XML);
if (track != null)
{
track.getValue(attrib, diagram.getUniverse().getCurTime());
return true;
}
//Return if we found presentation attribute
if (presAttr != null)
{
return true;
}
return false;
}
/**
* @param styName
* @return the raw presentation value of this attribute. Ignores any
* modifications applied by style attributes or animation. Used by
* animations to determine the starting point to animate from
*/
public StyleAttribute getPresAbsolute(String styName)
{
//Check for local inline styles
return (StyleAttribute) presAttribs.get(styName);
}
private static final Pattern TRANSFORM_PATTERN = Pattern.compile("\\w+\\([^)]*\\)");
static protected AffineTransform parseTransform(String val) throws SVGException
{
final Matcher matchExpression = TRANSFORM_PATTERN.matcher("");
AffineTransform retXform = new AffineTransform();
matchExpression.reset(val);
while (matchExpression.find())
{
retXform.concatenate(parseSingleTransform(matchExpression.group()));
}
return retXform;
}
private static final Pattern WORD_PATTERN = Pattern.compile("([a-zA-Z]+|-?\\d+(\\.\\d+)?([eE]-?\\d+)?|-?\\.\\d+([eE]-?\\d+)?)");
static public AffineTransform parseSingleTransform(String val) throws SVGException
{
final Matcher matchWord = WORD_PATTERN.matcher("");
AffineTransform retXform = new AffineTransform();
matchWord.reset(val);
if (!matchWord.find())
{
//Return identity transformation if no data present (eg, empty string)
return retXform;
}
String function = matchWord.group().toLowerCase();
LinkedList<String> termList = new LinkedList<String>();
while (matchWord.find())
{
termList.add(matchWord.group());
}
double[] terms = new double[termList.size()];
Iterator<String> it = termList.iterator();
int count = 0;
while (it.hasNext())
{
terms[count++] = XMLParseUtil.parseDouble(it.next());
}
//Calculate transformation
if (function.equals("matrix"))
{
retXform.setTransform(terms[0], terms[1], terms[2], terms[3], terms[4], terms[5]);
} else if (function.equals("translate"))
{
if (terms.length == 1)
{
retXform.setToTranslation(terms[0], 0);
} else
{
retXform.setToTranslation(terms[0], terms[1]);
}
} else if (function.equals("scale"))
{
if (terms.length > 1)
{
retXform.setToScale(terms[0], terms[1]);
} else
{
retXform.setToScale(terms[0], terms[0]);
}
} else if (function.equals("rotate"))
{
if (terms.length > 2)
{
retXform.setToRotation(Math.toRadians(terms[0]), terms[1], terms[2]);
} else
{
retXform.setToRotation(Math.toRadians(terms[0]));
}
} else if (function.equals("skewx"))
{
retXform.setToShear(Math.toRadians(terms[0]), 0.0);
} else if (function.equals("skewy"))
{
retXform.setToShear(0.0, Math.toRadians(terms[0]));
} else
{
throw new SVGException("Unknown transform type");
}
return retXform;
}
static protected PathCommand[] parsePathList(String list)
{
return new PathParser(list).parsePathCommand();
}
static protected GeneralPath buildPath(String text, int windingRule)
{
PathCommand[] commands = parsePathList(text);
int numKnots = 2;
for (int i = 0; i < commands.length; i++)
{
numKnots += commands[i].getNumKnotsAdded();
}
GeneralPath path = new GeneralPath(windingRule, numKnots);
BuildHistory hist = new BuildHistory();
for (int i = 0; i < commands.length; i++)
{
PathCommand cmd = commands[i];
cmd.appendPath(path, hist);
}
return path;
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @param curTime
* @return - true if this node has changed state as a result of the time
* update
* @throws SVGException
*/
abstract public boolean updateTime(double curTime) throws SVGException;
public int getNumChildren()
{
return children.size();
}
public SVGElement getChild(int i)
{
return (SVGElement) children.get(i);
}
public double lerp(double t0, double t1, double alpha)
{
return (1 - alpha) * t0 + alpha * t1;
}
}

View file

@ -0,0 +1,84 @@
/*
* 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 May 12, 2005, 11:32 PM
*/
package org.xbib.graphics.svg;
/**
*
* @author kitfox
*/
public class SVGElementException extends SVGException
{
public static final long serialVersionUID = 0;
private final SVGElement element;
/**
* Creates a new instance of <code>SVGException</code> without detail message.
* @param element
*/
public SVGElementException(SVGElement element)
{
this(element, null, null);
}
/**
* Constructs an instance of <code>SVGException</code> with the specified detail message.
* @param element
* @param msg the detail message.
*/
public SVGElementException(SVGElement element, String msg)
{
this(element, msg, null);
}
public SVGElementException(SVGElement element, String msg, Throwable cause)
{
super(msg, cause);
this.element = element;
}
public SVGElementException(SVGElement element, Throwable cause)
{
this(element, null, cause);
}
public SVGElement getElement()
{
return element;
}
}

View file

@ -0,0 +1,73 @@
/*
* 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 May 12, 2005, 11:32 PM
*/
package org.xbib.graphics.svg;
/**
*
* @author kitfox
*/
public class SVGException extends java.lang.Exception
{
public static final long serialVersionUID = 0;
/**
* Creates a new instance of <code>SVGException</code> without detail message.
*/
public SVGException()
{
}
/**
* Constructs an instance of <code>SVGException</code> with the specified detail message.
* @param msg the detail message.
*/
public SVGException(String msg)
{
super(msg);
}
public SVGException(String msg, Throwable cause)
{
super(msg, cause);
}
public SVGException(Throwable cause)
{
super(cause);
}
}

View file

@ -0,0 +1,308 @@
/*
* 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 February 18, 2004, 5:09 PM
*/
package org.xbib.graphics.svg;
import java.util.*;
import java.net.*;
import org.xbib.graphics.svg.animation.Animate;
import org.xbib.graphics.svg.animation.AnimateColor;
import org.xbib.graphics.svg.animation.AnimateMotion;
import org.xbib.graphics.svg.animation.AnimateTransform;
import org.xbib.graphics.svg.animation.SetSmil;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class SVGLoader extends DefaultHandler
{
final HashMap<String, Class<?>> nodeClasses = new HashMap<String, Class<?>>();
//final HashMap attribClasses = new HashMap();
final LinkedList<SVGElement> buildStack = new LinkedList<SVGElement>();
final HashSet<String> ignoreClasses = new HashSet<String>();
final SVGLoaderHelper helper;
/**
* The diagram that represents the base of this SVG document we're loading.
* Will be augmented to include node indexing info and other useful stuff.
*/
final SVGDiagram diagram;
// SVGElement loadRoot;
//Used to keep track of document elements that are not part of the SVG namespace
int skipNonSVGTagDepth = 0;
int indent = 0;
final boolean verbose;
/**
* Creates a new instance of SVGLoader
* @param xmlBase
* @param universe
*/
public SVGLoader(URI xmlBase, SVGUniverse universe)
{
this(xmlBase, universe, false);
}
public SVGLoader(URI xmlBase, SVGUniverse universe, boolean verbose)
{
this.verbose = verbose;
diagram = new SVGDiagram(xmlBase, universe);
//Compile a list of important builder classes
nodeClasses.put("a", A.class);
nodeClasses.put("animate", Animate.class);
nodeClasses.put("animatecolor", AnimateColor.class);
nodeClasses.put("animatemotion", AnimateMotion.class);
nodeClasses.put("animatetransform", AnimateTransform.class);
nodeClasses.put("circle", Circle.class);
nodeClasses.put("clippath", ClipPath.class);
nodeClasses.put("defs", Defs.class);
nodeClasses.put("desc", Desc.class);
nodeClasses.put("ellipse", Ellipse.class);
nodeClasses.put("filter", Filter.class);
nodeClasses.put(FeGaussianBlur.TAG_NAME, FeGaussianBlur.class);
nodeClasses.put("font", Font.class);
nodeClasses.put("font-face", FontFace.class);
nodeClasses.put("g", Group.class);
nodeClasses.put("glyph", Glyph.class);
nodeClasses.put("hkern", Hkern.class);
nodeClasses.put("image", ImageSVG.class);
nodeClasses.put("line", Line.class);
nodeClasses.put("lineargradient", LinearGradient.class);
nodeClasses.put("marker", Marker.class);
nodeClasses.put("mask", Mask.class);
nodeClasses.put("metadata", Metadata.class);
nodeClasses.put("missing-glyph", MissingGlyph.class);
nodeClasses.put("path", Path.class);
nodeClasses.put("pattern", PatternSVG.class);
nodeClasses.put("polygon", Polygon.class);
nodeClasses.put("polyline", Polyline.class);
nodeClasses.put("radialgradient", RadialGradient.class);
nodeClasses.put("rect", Rect.class);
nodeClasses.put("set", SetSmil.class);
nodeClasses.put("shape", ShapeElement.class);
nodeClasses.put("stop", Stop.class);
nodeClasses.put("style", Style.class);
nodeClasses.put("svg", SVGRoot.class);
nodeClasses.put("symbol", Symbol.class);
nodeClasses.put("text", Text.class);
nodeClasses.put("title", Title.class);
nodeClasses.put("tspan", Tspan.class);
nodeClasses.put("use", Use.class);
ignoreClasses.add("midpointstop");
//attribClasses.put("clip-path", StyleUrl.class);
//attribClasses.put("color", StyleColor.class);
helper = new SVGLoaderHelper(xmlBase, universe, diagram);
}
private String printIndent(int indent, String indentStrn)
{
StringBuffer sb = new StringBuffer();
for (int i = 0; i < indent; i++)
{
sb.append(indentStrn);
}
return sb.toString();
}
@Override
public void startDocument() throws SAXException
{
// System.err.println("Start doc");
// buildStack.clear();
}
@Override
public void endDocument() throws SAXException
{
// System.err.println("End doc");
}
@Override
public void startElement(String namespaceURI, String sName, String qName, Attributes attrs) throws SAXException
{
if (verbose)
{
System.err.println(printIndent(indent, " ") + "Starting parse of tag " + sName+ ": " + namespaceURI);
}
indent++;
if (skipNonSVGTagDepth != 0 || (!namespaceURI.equals("") && !namespaceURI.equals(SVGElement.SVG_NS)))
{
skipNonSVGTagDepth++;
return;
}
sName = sName.toLowerCase();
//javax.swing.JOptionPane.showMessageDialog(null, sName);
Object obj = nodeClasses.get(sName);
if (obj == null)
{
if (!ignoreClasses.contains(sName))
{
if (verbose)
{
System.err.println("SVGLoader: Could not identify tag '" + sName + "'");
}
}
return;
}
//Debug info tag depth
//for (int i = 0; i < buildStack.size(); i++) System.err.print(" ");
//System.err.println("+" + sName);
try {
Class<?> cls = (Class<?>)obj;
SVGElement svgEle = (SVGElement)cls.newInstance();
SVGElement parent = null;
if (buildStack.size() != 0) parent = (SVGElement)buildStack.getLast();
svgEle.loaderStartElement(helper, attrs, parent);
buildStack.addLast(svgEle);
}
catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not load", e);
throw new SAXException(e);
}
}
@Override
public void endElement(String namespaceURI, String sName, String qName)
throws SAXException
{
indent--;
if (verbose)
{
System.err.println(printIndent(indent, " ") + "Ending parse of tag " + sName+ ": " + namespaceURI);
}
if (skipNonSVGTagDepth != 0)
{
skipNonSVGTagDepth--;
return;
}
sName = sName.toLowerCase();
Object obj = nodeClasses.get(sName);
if (obj == null) return;
//Debug info tag depth
//for (int i = 0; i < buildStack.size(); i++) System.err.print(" ");
//System.err.println("-" + sName);
try {
SVGElement svgEle = (SVGElement)buildStack.removeLast();
svgEle.loaderEndElement(helper);
SVGElement parent = null;
if (buildStack.size() != 0)
{
parent = (SVGElement)buildStack.getLast();
}
//else loadRoot = (SVGElement)svgEle;
if (parent != null)
{
parent.loaderAddChild(helper, svgEle);
}
else
{
diagram.setRoot((SVGRoot)svgEle);
}
}
catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse", e);
throw new SAXException(e);
}
}
@Override
public void characters(char buf[], int offset, int len)
throws SAXException
{
if (skipNonSVGTagDepth != 0)
{
return;
}
if (buildStack.size() != 0)
{
SVGElement parent = (SVGElement)buildStack.getLast();
String s = new String(buf, offset, len);
parent.loaderAddText(helper, s);
}
}
@Override
public void processingInstruction(String target, String data)
throws SAXException
{
//Check for external style sheet
}
// public SVGElement getLoadRoot() { return loadRoot; }
public SVGDiagram getLoadedDiagram() { return diagram; }
}

View file

@ -0,0 +1,20 @@
package org.xbib.graphics.svg;
import java.net.URI;
public class SVGLoaderHelper
{
public final SVGUniverse universe;
public final SVGDiagram diagram;
public final URI xmlBase;
public SVGLoaderHelper(URI xmlBase, SVGUniverse universe, SVGDiagram diagram)
{
this.xmlBase = xmlBase;
this.universe = universe;
this.diagram = diagram;
}
}

View file

@ -0,0 +1,73 @@
/*
* 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 May 12, 2005, 11:32 PM
*/
package org.xbib.graphics.svg;
/**
*
* @author kitfox
*/
public class SVGParseException extends java.lang.Exception
{
public static final long serialVersionUID = 0;
/**
* Creates a new instance of <code>SVGException</code> without detail message.
*/
public SVGParseException()
{
}
/**
* Constructs an instance of <code>SVGException</code> with the specified detail message.
* @param msg the detail message.
*/
public SVGParseException(String msg)
{
super(msg);
}
public SVGParseException(String msg, Throwable cause)
{
super(msg, cause);
}
public SVGParseException(Throwable cause)
{
super(cause);
}
}

View file

@ -0,0 +1,496 @@
/*
* 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 February 18, 2004, 5:33 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.NumberWithUnits;
import org.xbib.graphics.svg.xml.StyleAttribute;
import org.xbib.graphics.svg.xml.StyleSheet;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.List;
/**
* The root element of an SVG tree.
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class SVGRoot extends Group
{
public static final String TAG_NAME = "svg";
NumberWithUnits x;
NumberWithUnits y;
NumberWithUnits width;
NumberWithUnits height;
Rectangle2D.Float viewBox = null;
public static final int PA_X_NONE = 0;
public static final int PA_X_MIN = 1;
public static final int PA_X_MID = 2;
public static final int PA_X_MAX = 3;
public static final int PA_Y_NONE = 0;
public static final int PA_Y_MIN = 1;
public static final int PA_Y_MID = 2;
public static final int PA_Y_MAX = 3;
public static final int PS_MEET = 0;
public static final int PS_SLICE = 1;
int parSpecifier = PS_MEET;
int parAlignX = PA_X_MID;
int parAlignY = PA_Y_MID;
final AffineTransform viewXform = new AffineTransform();
final Rectangle2D.Float clipRect = new Rectangle2D.Float();
private StyleSheet styleSheet;
/** Creates a new instance of SVGRoot */
public SVGRoot()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
public void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("x")))
{
x = sty.getNumberWithUnits();
}
if (getPres(sty.setName("y")))
{
y = sty.getNumberWithUnits();
}
if (getPres(sty.setName("width")))
{
width = sty.getNumberWithUnits();
}
if (getPres(sty.setName("height")))
{
height = sty.getNumberWithUnits();
}
if (getPres(sty.setName("viewBox")))
{
float[] coords = sty.getFloatList();
viewBox = new Rectangle2D.Float(coords[0], coords[1], coords[2], coords[3]);
}
if (getPres(sty.setName("preserveAspectRatio")))
{
String preserve = sty.getStringValue();
if (contains(preserve, "none")) { parAlignX = PA_X_NONE; parAlignY = PA_Y_NONE; }
else if (contains(preserve, "xMinYMin")) { parAlignX = PA_X_MIN; parAlignY = PA_Y_MIN; }
else if (contains(preserve, "xMidYMin")) { parAlignX = PA_X_MID; parAlignY = PA_Y_MIN; }
else if (contains(preserve, "xMaxYMin")) { parAlignX = PA_X_MAX; parAlignY = PA_Y_MIN; }
else if (contains(preserve, "xMinYMid")) { parAlignX = PA_X_MIN; parAlignY = PA_Y_MID; }
else if (contains(preserve, "xMidYMid")) { parAlignX = PA_X_MID; parAlignY = PA_Y_MID; }
else if (contains(preserve, "xMaxYMid")) { parAlignX = PA_X_MAX; parAlignY = PA_Y_MID; }
else if (contains(preserve, "xMinYMax")) { parAlignX = PA_X_MIN; parAlignY = PA_Y_MAX; }
else if (contains(preserve, "xMidYMax")) { parAlignX = PA_X_MID; parAlignY = PA_Y_MAX; }
else if (contains(preserve, "xMaxYMax")) { parAlignX = PA_X_MAX; parAlignY = PA_Y_MAX; }
if (contains(preserve, "meet"))
{
parSpecifier = PS_MEET;
}
else if (contains(preserve, "slice"))
{
parSpecifier = PS_SLICE;
}
}
prepareViewport();
}
private boolean contains(String text, String find)
{
return (text.indexOf(find) != -1);
}
@Override
public SVGRoot getRoot()
{
return this;
}
protected void prepareViewport()
{
Rectangle deviceViewport = diagram.getDeviceViewport();
Rectangle2D defaultBounds;
try
{
defaultBounds = getBoundingBox();
}
catch (SVGException ex)
{
defaultBounds= new Rectangle2D.Float();
}
//Determine destination rectangle
float xx, yy, ww, hh;
if (width != null)
{
xx = (x == null) ? 0 : StyleAttribute.convertUnitsToPixels(x.getUnits(), x.getValue());
if (width.getUnits() == NumberWithUnits.UT_PERCENT)
{
ww = width.getValue() * deviceViewport.width;
}
else
{
ww = StyleAttribute.convertUnitsToPixels(width.getUnits(), width.getValue());
}
}
else if (viewBox != null)
{
xx = viewBox.x;
ww = viewBox.width;
width = new NumberWithUnits(ww, NumberWithUnits.UT_PX);
x = new NumberWithUnits(xx, NumberWithUnits.UT_PX);
}
else
{
//Estimate size from scene bounding box
xx = (float)defaultBounds.getX();
ww = (float)defaultBounds.getWidth();
width = new NumberWithUnits(ww, NumberWithUnits.UT_PX);
x = new NumberWithUnits(xx, NumberWithUnits.UT_PX);
}
if (height != null)
{
yy = (y == null) ? 0 : StyleAttribute.convertUnitsToPixels(y.getUnits(), y.getValue());
if (height.getUnits() == NumberWithUnits.UT_PERCENT)
{
hh = height.getValue() * deviceViewport.height;
}
else
{
hh = StyleAttribute.convertUnitsToPixels(height.getUnits(), height.getValue());
}
}
else if (viewBox != null)
{
yy = viewBox.y;
hh = viewBox.height;
height = new NumberWithUnits(hh, NumberWithUnits.UT_PX);
y = new NumberWithUnits(yy, NumberWithUnits.UT_PX);
}
else
{
//Estimate size from scene bounding box
yy = (float)defaultBounds.getY();
hh = (float)defaultBounds.getHeight();
height = new NumberWithUnits(hh, NumberWithUnits.UT_PX);
y = new NumberWithUnits(yy, NumberWithUnits.UT_PX);
}
clipRect.setRect(xx, yy, ww, hh);
}
public void renderToViewport(Graphics2D g) throws SVGException
{
render(g);
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
prepareViewport();
Rectangle targetViewport = g.getClipBounds();
//
// if (targetViewport == null)
// {
// Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
// targetViewport = new Rectangle(0, 0, size.width, size.height);
// }
// clipRect.setRect(targetViewport);
Rectangle deviceViewport = diagram.getDeviceViewport();
if (width != null && height != null)
{
float xx, yy, ww, hh;
xx = (x == null) ? 0 : StyleAttribute.convertUnitsToPixels(x.getUnits(), x.getValue());
if (width.getUnits() == NumberWithUnits.UT_PERCENT)
{
ww = width.getValue() * deviceViewport.width;
}
else
{
ww = StyleAttribute.convertUnitsToPixels(width.getUnits(), width.getValue());
}
yy = (y == null) ? 0 : StyleAttribute.convertUnitsToPixels(y.getUnits(), y.getValue());
if (height.getUnits() == NumberWithUnits.UT_PERCENT)
{
hh = height.getValue() * deviceViewport.height;
}
else
{
hh = StyleAttribute.convertUnitsToPixels(height.getUnits(), height.getValue());
}
targetViewport = new Rectangle((int)xx, (int)yy, (int)ww, (int)hh);
}
else
{
targetViewport = new Rectangle(deviceViewport);
}
clipRect.setRect(targetViewport);
viewXform.setTransform(calcViewportTransform(targetViewport));
AffineTransform cachedXform = g.getTransform();
g.transform(viewXform);
super.doRender(g);
g.setTransform(cachedXform);
}
public AffineTransform calcViewportTransform(Rectangle targetViewport)
{
AffineTransform xform = new AffineTransform();
if (viewBox == null)
{
xform.setToIdentity();
}
else
{
xform.setToIdentity();
xform.setToTranslation(targetViewport.x, targetViewport.y);
xform.scale(targetViewport.width, targetViewport.height);
xform.scale(1 / viewBox.width, 1 / viewBox.height);
xform.translate(-viewBox.x, -viewBox.y);
}
return xform;
}
@Override
public void doPick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
{
if (viewXform != null)
{
ltw = new AffineTransform(ltw);
ltw.concatenate(viewXform);
}
super.doPick(pickArea, ltw, boundingBox, retVec);
}
@Override
public void doPick(Point2D point, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
{
Point2D xPoint = new Point2D.Double(point.getX(), point.getY());
if (viewXform != null)
{
try
{
viewXform.inverseTransform(point, xPoint);
} catch (NoninvertibleTransformException ex)
{
throw new SVGException(ex);
}
}
super.doPick(xPoint, boundingBox, retVec);
}
@Override
public Shape getShape()
{
Shape shape = super.getShape();
return viewXform.createTransformedShape(shape);
}
@Override
public Rectangle2D getBoundingBox() throws SVGException
{
Rectangle2D bbox = super.getBoundingBox();
return viewXform.createTransformedShape(bbox).getBounds2D();
}
public float getDeviceWidth()
{
return clipRect.width;
}
public float getDeviceHeight()
{
return clipRect.height;
}
public Rectangle2D getDeviceRect(Rectangle2D rect)
{
rect.setRect(clipRect);
return rect;
}
/**
* Updates all attributes in this diagram associated with a time event.
* Ie, all attributes with track information.
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
boolean changeState = super.updateTime(curTime);
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getPres(sty.setName("x")))
{
NumberWithUnits newVal = sty.getNumberWithUnits();
if (!newVal.equals(x))
{
x = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("y")))
{
NumberWithUnits newVal = sty.getNumberWithUnits();
if (!newVal.equals(y))
{
y = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("width")))
{
NumberWithUnits newVal = sty.getNumberWithUnits();
if (!newVal.equals(width))
{
width = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("height")))
{
NumberWithUnits newVal = sty.getNumberWithUnits();
if (!newVal.equals(height))
{
height = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("viewBox")))
{
float[] coords = sty.getFloatList();
Rectangle2D.Float newViewBox = new Rectangle2D.Float(coords[0], coords[1], coords[2], coords[3]);
if (!newViewBox.equals(viewBox))
{
viewBox = newViewBox;
shapeChange = true;
}
}
if (shapeChange)
{
build();
}
return changeState || shapeChange;
}
/**
* @return the styleSheet
*/
public StyleSheet getStyleSheet()
{
if (styleSheet == null)
{
for (int i = 0; i < getNumChildren(); ++i)
{
SVGElement ele = getChild(i);
if (ele instanceof Style)
{
return ((Style)ele).getStyleSheet();
}
else if (ele instanceof Defs)
{
return ((Defs)ele).getStyleSheet();
}
}
}
return styleSheet;
}
/**
* @param styleSheet the styleSheet to set
*/
public void setStyleSheet(StyleSheet styleSheet)
{
this.styleSheet = styleSheet;
}
}

View file

@ -0,0 +1,733 @@
/*
* 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 February 18, 2004, 11:43 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.app.beans.SVGIcon;
import org.xbib.graphics.svg.util.Base64InputStream;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Reader;
import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream;
import javax.imageio.ImageIO;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
/**
* Many SVG files can be loaded at one time. These files will quite likely need
* to reference one another. The SVG universe provides a container for all these
* files and the means for them to relate to each other.
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class SVGUniverse implements Serializable
{
public static final long serialVersionUID = 0;
transient private PropertyChangeSupport changes = new PropertyChangeSupport(this);
/**
* Maps document URIs to their loaded SVG diagrams. Note that URIs for
* documents loaded from URLs will reflect their URLs and URIs for documents
* initiated from streams will have the scheme <i>svgSalamander</i>.
*/
final HashMap<URI, SVGDiagram> loadedDocs = new HashMap<URI, SVGDiagram>();
final HashMap<String, Font> loadedFonts = new HashMap<String, Font>();
final HashMap<URL, SoftReference<BufferedImage>> loadedImages = new HashMap<URL, SoftReference<BufferedImage>>();
public static final String INPUTSTREAM_SCHEME = "svgSalamander";
/**
* Current time in this universe. Used for resolving attributes that are
* influenced by track information. Time is in milliseconds. Time 0
* corresponds to the time of 0 in each member diagram.
*/
protected double curTime = 0.0;
private boolean verbose = false;
//If true, <imageSVG> elements will only load image data that is included using inline data: uris
private boolean imageDataInlineOnly = false;
/**
* Creates a new instance of SVGUniverse
*/
public SVGUniverse()
{
}
public void addPropertyChangeListener(PropertyChangeListener l)
{
changes.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l)
{
changes.removePropertyChangeListener(l);
}
/**
* Release all loaded SVG document from memory
*/
public void clear()
{
loadedDocs.clear();
loadedFonts.clear();
loadedImages.clear();
}
/**
* Returns the current animation time in milliseconds.
*/
public double getCurTime()
{
return curTime;
}
public void setCurTime(double curTime)
{
double oldTime = this.curTime;
this.curTime = curTime;
changes.firePropertyChange("curTime", new Double(oldTime), new Double(curTime));
}
/**
* Updates all time influenced style and presentation attributes in all SVG
* documents in this universe.
*/
public void updateTime() throws SVGException
{
for (SVGDiagram dia : loadedDocs.values()) {
dia.updateTime(curTime);
}
}
/**
* Called by the Font element to let the universe know that a font has been
* loaded and is available.
*/
void registerFont(Font font)
{
loadedFonts.put(font.getFontFace().getFontFamily(), font);
}
public Font getDefaultFont()
{
for (Font font : loadedFonts.values()) {
return font;
}
return null;
}
public Font getFont(String fontName)
{
return (Font) loadedFonts.get(fontName);
}
URL registerImage(URI imageURI)
{
String scheme = imageURI.getScheme();
if (scheme.equals("data"))
{
String path = imageURI.getRawSchemeSpecificPart();
int idx = path.indexOf(';');
String mime = path.substring(0, idx);
String content = path.substring(idx + 1);
if (content.startsWith("base64"))
{
content = content.substring(6);
try
{
// byte[] buf = new sun.misc.BASE64Decoder().decodeBuffer(content);
// ByteArrayInputStream bais = new ByteArrayInputStream(buf);
ByteArrayInputStream bis = new ByteArrayInputStream(content.getBytes());
Base64InputStream bais = new Base64InputStream(bis);
BufferedImage img = ImageIO.read(bais);
URL url;
int urlIdx = 0;
while (true)
{
url = new URL("inlineImage", "localhost", "img" + urlIdx);
if (!loadedImages.containsKey(url))
{
break;
}
urlIdx++;
}
SoftReference<BufferedImage> ref = new SoftReference<BufferedImage>(img);
loadedImages.put(url, ref);
return url;
} catch (IOException ex)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not decode inline image", ex);
}
}
return null;
} else
{
try
{
URL url = imageURI.toURL();
registerImage(url);
return url;
} catch (MalformedURLException ex)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Bad url", ex);
}
return null;
}
}
void registerImage(URL imageURL)
{
if (loadedImages.containsKey(imageURL))
{
return;
}
SoftReference<BufferedImage> ref;
try
{
String fileName = imageURL.getFile();
if (".svg".equals(fileName.substring(fileName.length() - 4).toLowerCase()))
{
SVGIcon icon = new SVGIcon();
icon.setSvgURI(imageURL.toURI());
BufferedImage img = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = img.createGraphics();
icon.paintIcon(null, g, 0, 0);
g.dispose();
ref = new SoftReference<BufferedImage>(img);
} else
{
BufferedImage img = ImageIO.read(imageURL);
ref = new SoftReference<BufferedImage>(img);
}
loadedImages.put(imageURL, ref);
} catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not load image: " + imageURL, e);
}
}
BufferedImage getImage(URL imageURL)
{
SoftReference<BufferedImage> ref = (SoftReference<BufferedImage>) loadedImages.get(imageURL);
if (ref == null)
{
return null;
}
BufferedImage img = (BufferedImage) ref.get();
//If image was cleared from memory, reload it
if (img == null)
{
try
{
img = ImageIO.read(imageURL);
} catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not load image", e);
}
ref = new SoftReference<BufferedImage>(img);
loadedImages.put(imageURL, ref);
}
return img;
}
/**
* Returns the element of the document at the given URI. If the document is
* not already loaded, it will be.
*/
public SVGElement getElement(URI path)
{
return getElement(path, true);
}
public SVGElement getElement(URL path)
{
try
{
URI uri = new URI(path.toString());
return getElement(uri, true);
} catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse url " + path, e);
}
return null;
}
public URI cleanUri(URI uri)
{
String scheme = uri.getScheme();
String schemeSpecific = uri.getSchemeSpecificPart();
String frag = uri.getFragment();
if (schemeSpecific.startsWith("file:///"))
{
//Work around for URIs of resources obtained by Class.getResource()
schemeSpecific = "file:/" + schemeSpecific.substring(8);
}
else
{
return uri;
}
try
{
return new URI(scheme, schemeSpecific, frag);
}
catch (URISyntaxException ex)
{
Logger.getLogger(SVGUniverse.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
/**
* Looks up a href within our universe. If the href refers to a document
* that is not loaded, it will be loaded. The URL #target will then be
* checked against the SVG diagram's index and the corresponding element
* returned. If there is no corresponding index, null is returned.
*/
public SVGElement getElement(URI path, boolean loadIfAbsent)
{
try
{
path = cleanUri(path);
//Strip fragment from URI
URI xmlBase = new URI(path.getScheme(), path.getSchemeSpecificPart(), null);
SVGDiagram dia = (SVGDiagram) loadedDocs.get(xmlBase);
if (dia == null && loadIfAbsent)
{
//System.err.println("SVGUnivserse: " + xmlBase.toString());
//javax.swing.JOptionPane.showMessageDialog(null, xmlBase.toString());
URL url = xmlBase.toURL();
loadSVG(url, false);
dia = (SVGDiagram) loadedDocs.get(xmlBase);
if (dia == null)
{
return null;
}
}
String fragment = path.getFragment();
return fragment == null ? dia.getRoot() : dia.getElement(fragment);
} catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse path " + path, e);
return null;
}
}
public SVGDiagram getDiagram(URI xmlBase)
{
return getDiagram(xmlBase, true);
}
/**
* Returns the diagram that has been loaded from this root. If diagram is
* not already loaded, returns null.
*/
public SVGDiagram getDiagram(URI xmlBase, boolean loadIfAbsent)
{
if (xmlBase == null)
{
return null;
}
SVGDiagram dia = (SVGDiagram) loadedDocs.get(xmlBase);
if (dia != null || !loadIfAbsent)
{
return dia;
}
//Load missing diagram
try
{
URL url;
if ("jar".equals(xmlBase.getScheme()) && xmlBase.getPath() != null && !xmlBase.getPath().contains("!/"))
{
//Workaround for resources stored in jars loaded by Webstart.
//http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6753651
url = SVGUniverse.class.getResource(xmlBase.getPath());
}
else
{
url = xmlBase.toURL();
}
loadSVG(url, false);
dia = (SVGDiagram) loadedDocs.get(xmlBase);
return dia;
} catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse", e);
}
return null;
}
/**
* Wraps input stream in a BufferedInputStream. If it is detected that this
* input stream is GZIPped, also wraps in a GZIPInputStream for inflation.
*
* @param is Raw input stream
* @return Uncompressed stream of SVG data
* @throws java.io.IOException
*/
private InputStream createDocumentInputStream(InputStream is) throws IOException
{
BufferedInputStream bin = new BufferedInputStream(is);
bin.mark(2);
int b0 = bin.read();
int b1 = bin.read();
bin.reset();
//Check for gzip magic number
if ((b1 << 8 | b0) == GZIPInputStream.GZIP_MAGIC)
{
GZIPInputStream iis = new GZIPInputStream(bin);
return iis;
} else
{
//Plain text
return bin;
}
}
public URI loadSVG(URL docRoot)
{
return loadSVG(docRoot, false);
}
/**
* Loads an SVG file and all the files it references from the URL provided.
* If a referenced file already exists in the SVG universe, it is not
* reloaded.
*
* @param docRoot - URL to the location where this SVG file can be found.
* @param forceLoad - if true, ignore cached diagram and reload
* @return - The URI that refers to the loaded document
*/
public URI loadSVG(URL docRoot, boolean forceLoad)
{
try
{
URI uri = new URI(docRoot.toString());
if (loadedDocs.containsKey(uri) && !forceLoad)
{
return uri;
}
InputStream is = docRoot.openStream();
URI result = loadSVG(uri, new InputSource(createDocumentInputStream(is)));
is.close();
return result;
} catch (URISyntaxException ex)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse", ex);
} catch (IOException e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse", e);
}
return null;
}
public URI loadSVG(InputStream is, String name) throws IOException
{
return loadSVG(is, name, false);
}
public URI loadSVG(InputStream is, String name, boolean forceLoad) throws IOException
{
URI uri = getStreamBuiltURI(name);
if (uri == null)
{
return null;
}
if (loadedDocs.containsKey(uri) && !forceLoad)
{
return uri;
}
return loadSVG(uri, new InputSource(createDocumentInputStream(is)));
}
public URI loadSVG(Reader reader, String name)
{
return loadSVG(reader, name, false);
}
/**
* This routine allows you to create SVG documents from data streams that
* may not necessarily have a URL to load from. Since every SVG document
* must be identified by a unique URL, Salamander provides a method to fake
* this for streams by defining it's own protocol - svgSalamander - for SVG
* documents without a formal URL.
*
* @param reader - A stream containing a valid SVG document
* @param name - <p>A unique name for this document. It will be used to
* construct a unique URI to refer to this document and perform resolution
* with relative URIs within this document.</p> <p>For example, a name of
* "/myScene" will produce the URI svgSalamander:/myScene.
* "/maps/canada/toronto" will produce svgSalamander:/maps/canada/toronto.
* If this second document then contained the href "../uk/london", it would
* resolve by default to svgSalamander:/maps/uk/london. That is, SVG
* Salamander defines the URI scheme svgSalamander for it's own internal use
* and uses it for uniquely identfying documents loaded by stream.</p> <p>If
* you need to link to documents outside of this scheme, you can either
* supply full hrefs (eg, href="url(http://www.kitfox.com/index.html)") or
* put the xml:base attribute in a tag to change the defaultbase URIs are
* resolved against</p> <p>If a name does not start with the character '/',
* it will be automatically prefixed to it.</p>
* @param forceLoad - if true, ignore cached diagram and reload
*
* @return - The URI that refers to the loaded document
*/
public URI loadSVG(Reader reader, String name, boolean forceLoad)
{
//System.err.println(url.toString());
//Synthesize URI for this stream
URI uri = getStreamBuiltURI(name);
if (uri == null)
{
return null;
}
if (loadedDocs.containsKey(uri) && !forceLoad)
{
return uri;
}
return loadSVG(uri, new InputSource(reader));
}
/**
* Synthesize a URI for an SVGDiagram constructed from a stream.
*
* @param name - Name given the document constructed from a stream.
*/
public URI getStreamBuiltURI(String name)
{
if (name == null || name.length() == 0)
{
return null;
}
if (name.charAt(0) != '/')
{
name = '/' + name;
}
try
{
//Dummy URL for SVG documents built from image streams
return new URI(INPUTSTREAM_SCHEME, name, null);
} catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not parse", e);
return null;
}
}
static ThreadLocal<SAXParser> threadSAXParser = new ThreadLocal<SAXParser>();
private XMLReader getXMLReader() throws SAXException, ParserConfigurationException
{
SAXParser saxParser = threadSAXParser.get();
if (saxParser == null)
{
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
saxParserFactory.setNamespaceAware(true);
saxParser = saxParserFactory.newSAXParser();
threadSAXParser.set(saxParser);
}
return saxParser.getXMLReader();
}
protected URI loadSVG(URI xmlBase, InputSource is)
{
xmlBase = cleanUri(xmlBase);
// Use an instance of ourselves as the SAX event handler
SVGLoader handler = new SVGLoader(xmlBase, this, verbose);
//Place this docment in the universe before it is completely loaded
// so that the load process can refer to references within it's current
// document
loadedDocs.put(xmlBase, handler.getLoadedDiagram());
try
{
// Parse the input
XMLReader reader = getXMLReader();
reader.setEntityResolver(
new EntityResolver()
{
public InputSource resolveEntity(String publicId, String systemId)
{
//Ignore all DTDs
return new InputSource(new ByteArrayInputStream(new byte[0]));
}
});
reader.setContentHandler(handler);
reader.parse(is);
handler.getLoadedDiagram().updateTime(curTime);
return xmlBase;
} catch (SAXParseException sex)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Error processing " + xmlBase, sex);
loadedDocs.remove(xmlBase);
return null;
} catch (Throwable e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not load SVG " + xmlBase, e);
}
return null;
}
/**
* Get list of uris of all loaded documents and subdocuments.
* @return
*/
public ArrayList<URI> getLoadedDocumentURIs()
{
return new ArrayList<URI>(loadedDocs.keySet());
}
/**
* Remove loaded document from cache.
* @param uri
*/
public void removeDocument(URI uri)
{
uri = cleanUri(uri);
loadedDocs.remove(uri);
}
public boolean isVerbose()
{
return verbose;
}
public void setVerbose(boolean verbose)
{
this.verbose = verbose;
}
/**
* Uses serialization to duplicate this universe.
*/
public SVGUniverse duplicate() throws IOException, ClassNotFoundException
{
ByteArrayOutputStream bs = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bs);
os.writeObject(this);
os.close();
ByteArrayInputStream bin = new ByteArrayInputStream(bs.toByteArray());
ObjectInputStream is = new ObjectInputStream(bin);
SVGUniverse universe = (SVGUniverse) is.readObject();
is.close();
return universe;
}
/**
* @return the imageDataInlineOnly
*/
public boolean isImageDataInlineOnly()
{
return imageDataInlineOnly;
}
/**
* @param imageDataInlineOnly the imageDataInlineOnly to set
*/
public void setImageDataInlineOnly(boolean imageDataInlineOnly)
{
this.imageDataInlineOnly = imageDataInlineOnly;
}
}

View file

@ -0,0 +1,448 @@
/*
* 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 January 26, 2004, 5:21 PM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.Marker.MarkerLayout;
import org.xbib.graphics.svg.Marker.MarkerPos;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
/**
* Parent of shape objects
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
abstract public class ShapeElement extends RenderableElement
{
/**
* This is necessary to get text elements to render the stroke the correct
* width. It is an alternative to producing new font glyph sets at different
* sizes.
*/
protected float strokeWidthScalar = 1f;
/** Creates a new instance of ShapeElement */
public ShapeElement() {
}
@Override
abstract protected void doRender(java.awt.Graphics2D g) throws SVGException;
/*
protected void setStrokeWidthScalar(float strokeWidthScalar)
{
this.strokeWidthScalar = strokeWidthScalar;
}
*/
@Override
protected void doPick(Point2D point, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
{
// StyleAttribute styleAttrib = new StyleAttribute();
// if (getStyle(styleAttrib.setName("fill")) && getShape().contains(point))
if ((boundingBox ? getBoundingBox() : getShape()).contains(point))
{
retVec.add(getPath(null));
}
}
@Override
protected void doPick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException
{
// StyleAttribute styleAttrib = new StyleAttribute();
// if (getStyle(styleAttrib.setName("fill")) && getShape().contains(point))
if (ltw.createTransformedShape((boundingBox ? getBoundingBox() : getShape())).intersects(pickArea))
{
retVec.add(getPath(null));
}
}
private Paint handleCurrentColor(StyleAttribute styleAttrib) throws SVGException
{
if (styleAttrib.getStringValue().equals("currentColor"))
{
StyleAttribute currentColorAttrib = new StyleAttribute();
if (getStyle(currentColorAttrib.setName("color")))
{
if (!currentColorAttrib.getStringValue().equals("none"))
{
return currentColorAttrib.getColorValue();
}
}
return null;
}
else
{
return styleAttrib.getColorValue();
}
}
protected void renderShape(Graphics2D g, Shape shape) throws SVGException
{
//g.setColor(Color.green);
StyleAttribute styleAttrib = new StyleAttribute();
//Don't process if not visible
if (getStyle(styleAttrib.setName("visibility")))
{
if (!styleAttrib.getStringValue().equals("visible")) return;
}
if (getStyle(styleAttrib.setName("display")))
{
if (styleAttrib.getStringValue().equals("none")) return;
}
//None, solid color, gradient, pattern
Paint fillPaint = Color.black; //Default to black. Must be explicitly set to none for no fill.
if (getStyle(styleAttrib.setName("fill")))
{
if (styleAttrib.getStringValue().equals("none")) fillPaint = null;
else
{
fillPaint = handleCurrentColor(styleAttrib);
if (fillPaint == null)
{
URI uri = styleAttrib.getURIValue(getXMLBase());
if (uri != null)
{
Rectangle2D bounds = shape.getBounds2D();
AffineTransform xform = g.getTransform();
SVGElement ele = diagram.getUniverse().getElement(uri);
if (ele != null)
{
try {
fillPaint = ((FillElement)ele).getPaint(bounds, xform);
} catch (IllegalArgumentException e) {
throw new SVGException(e);
}
}
}
}
}
}
//Default opacity
float opacity = 1f;
if (getStyle(styleAttrib.setName("opacity")))
{
opacity = styleAttrib.getRatioValue();
}
float fillOpacity = opacity;
if (getStyle(styleAttrib.setName("fill-opacity")))
{
fillOpacity *= styleAttrib.getRatioValue();
}
Paint strokePaint = null; //Default is to stroke with none
if (getStyle(styleAttrib.setName("stroke")))
{
if (styleAttrib.getStringValue().equals("none")) strokePaint = null;
else
{
strokePaint = handleCurrentColor(styleAttrib);
if (strokePaint == null)
{
URI uri = styleAttrib.getURIValue(getXMLBase());
if (uri != null)
{
Rectangle2D bounds = shape.getBounds2D();
AffineTransform xform = g.getTransform();
SVGElement ele = diagram.getUniverse().getElement(uri);
if (ele != null)
{
strokePaint = ((FillElement)ele).getPaint(bounds, xform);
}
}
}
}
}
float[] strokeDashArray = null;
if (getStyle(styleAttrib.setName("stroke-dasharray")))
{
strokeDashArray = styleAttrib.getFloatList();
if (strokeDashArray.length == 0) strokeDashArray = null;
}
float strokeDashOffset = 0f;
if (getStyle(styleAttrib.setName("stroke-dashoffset")))
{
strokeDashOffset = styleAttrib.getFloatValueWithUnits();
}
int strokeLinecap = BasicStroke.CAP_BUTT;
if (getStyle(styleAttrib.setName("stroke-linecap")))
{
String val = styleAttrib.getStringValue();
if (val.equals("round"))
{
strokeLinecap = BasicStroke.CAP_ROUND;
}
else if (val.equals("square"))
{
strokeLinecap = BasicStroke.CAP_SQUARE;
}
}
int strokeLinejoin = BasicStroke.JOIN_MITER;
if (getStyle(styleAttrib.setName("stroke-linejoin")))
{
String val = styleAttrib.getStringValue();
if (val.equals("round"))
{
strokeLinejoin = BasicStroke.JOIN_ROUND;
}
else if (val.equals("bevel"))
{
strokeLinejoin = BasicStroke.JOIN_BEVEL;
}
}
float strokeMiterLimit = 4f;
if (getStyle(styleAttrib.setName("stroke-miterlimit")))
{
strokeMiterLimit = Math.max(styleAttrib.getFloatValueWithUnits(), 1);
}
float strokeOpacity = opacity;
if (getStyle(styleAttrib.setName("stroke-opacity")))
{
strokeOpacity *= styleAttrib.getRatioValue();
}
float strokeWidth = 1f;
if (getStyle(styleAttrib.setName("stroke-width")))
{
strokeWidth = styleAttrib.getFloatValueWithUnits();
}
// if (strokeWidthScalar != 1f)
// {
strokeWidth *= strokeWidthScalar;
// }
Marker markerStart = null;
if (getStyle(styleAttrib.setName("marker-start")))
{
if (!styleAttrib.getStringValue().equals("none"))
{
URI uri = styleAttrib.getURIValue(getXMLBase());
markerStart = (Marker)diagram.getUniverse().getElement(uri);
}
}
Marker markerMid = null;
if (getStyle(styleAttrib.setName("marker-mid")))
{
if (!styleAttrib.getStringValue().equals("none"))
{
URI uri = styleAttrib.getURIValue(getXMLBase());
markerMid = (Marker)diagram.getUniverse().getElement(uri);
}
}
Marker markerEnd = null;
if (getStyle(styleAttrib.setName("marker-end")))
{
if (!styleAttrib.getStringValue().equals("none"))
{
URI uri = styleAttrib.getURIValue(getXMLBase());
markerEnd = (Marker)diagram.getUniverse().getElement(uri);
}
}
//Draw the shape
if (fillPaint != null && fillOpacity != 0f)
{
if (fillOpacity <= 0)
{
//Do nothing
}
else if (fillOpacity < 1f)
{
Composite cachedComposite = g.getComposite();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, fillOpacity));
g.setPaint(fillPaint);
g.fill(shape);
g.setComposite(cachedComposite);
}
else
{
g.setPaint(fillPaint);
g.fill(shape);
}
}
if (strokePaint != null && strokeOpacity != 0f)
{
BasicStroke stroke;
if (strokeDashArray == null)
{
stroke = new BasicStroke(strokeWidth, strokeLinecap, strokeLinejoin, strokeMiterLimit);
}
else
{
stroke = new BasicStroke(strokeWidth, strokeLinecap, strokeLinejoin, strokeMiterLimit, strokeDashArray, strokeDashOffset);
}
Shape strokeShape;
AffineTransform cacheXform = g.getTransform();
if (vectorEffect == VECTOR_EFFECT_NON_SCALING_STROKE)
{
strokeShape = cacheXform.createTransformedShape(shape);
strokeShape = stroke.createStrokedShape(strokeShape);
}
else
{
strokeShape = stroke.createStrokedShape(shape);
}
if (strokeOpacity <= 0)
{
//Do nothing
}
else
{
Composite cachedComposite = g.getComposite();
if (strokeOpacity < 1f)
{
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, strokeOpacity));
}
if (vectorEffect == VECTOR_EFFECT_NON_SCALING_STROKE)
{
//Set to identity
g.setTransform(new AffineTransform());
}
g.setPaint(strokePaint);
g.fill(strokeShape);
if (vectorEffect == VECTOR_EFFECT_NON_SCALING_STROKE)
{
//Set to identity
g.setTransform(cacheXform);
}
if (strokeOpacity < 1f)
{
g.setComposite(cachedComposite);
}
}
}
if (markerStart != null || markerMid != null || markerEnd != null)
{
MarkerLayout layout = new MarkerLayout();
layout.layout(shape);
ArrayList<MarkerPos> list = layout.getMarkerList();
for (int i = 0; i < list.size(); ++i)
{
MarkerPos pos = list.get(i);
switch (pos.type)
{
case Marker.MARKER_START:
if (markerStart != null)
{
markerStart.render(g, pos, strokeWidth);
}
break;
case Marker.MARKER_MID:
if (markerMid != null)
{
markerMid.render(g, pos, strokeWidth);
}
break;
case Marker.MARKER_END:
if (markerEnd != null)
{
markerEnd.render(g, pos, strokeWidth);
}
break;
}
}
}
}
abstract public Shape getShape();
protected Rectangle2D includeStrokeInBounds(Rectangle2D rect) throws SVGException
{
StyleAttribute styleAttrib = new StyleAttribute();
if (!getStyle(styleAttrib.setName("stroke"))) return rect;
double strokeWidth = 1;
if (getStyle(styleAttrib.setName("stroke-width"))) strokeWidth = styleAttrib.getDoubleValue();
rect.setRect(
rect.getX() - strokeWidth / 2,
rect.getY() - strokeWidth / 2,
rect.getWidth() + strokeWidth,
rect.getHeight() + strokeWidth);
return rect;
}
}

View file

@ -0,0 +1,150 @@
/*
* 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 January 26, 2004, 1:56 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Color;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Stop extends SVGElement
{
public static final String TAG_NAME = "stop";
float offset = 0f;
float opacity = 1f;
Color color = Color.black;
/**
* Creates a new instance of Stop
*/
public Stop()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("offset")))
{
offset = sty.getFloatValue();
String units = sty.getUnits();
if (units != null && units.equals("%"))
{
offset /= 100f;
}
if (offset > 1)
{
offset = 1;
}
if (offset < 0)
{
offset = 0;
}
}
if (getStyle(sty.setName("stop-color")))
{
color = sty.getColorValue();
}
if (getStyle(sty.setName("stop-opacity")))
{
opacity = sty.getRatioValue();
}
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getPres(sty.setName("offset")))
{
float newVal = sty.getFloatValue();
if (newVal != offset)
{
offset = newVal;
shapeChange = true;
}
}
if (getStyle(sty.setName("stop-color")))
{
Color newVal = sty.getColorValue();
if (newVal != color)
{
color = newVal;
shapeChange = true;
}
}
if (getStyle(sty.setName("stop-opacity")))
{
float newVal = sty.getFloatValue();
if (newVal != opacity)
{
opacity = newVal;
shapeChange = true;
}
}
return shapeChange;
}
}

View file

@ -0,0 +1,110 @@
/*
* 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 September 19, 2004, 1:56 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import org.xbib.graphics.svg.xml.StyleSheet;
/**
* Holds title textual information within tree
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Style extends SVGElement
{
public static final String TAG_NAME = "style";
//Should be set to "text/css"
String type;
StringBuffer text = new StringBuffer();
StyleSheet styleSheet;
/**
* Creates a new instance of Stop
*/
public Style()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Called during load process to add text scanned within a tag
*/
@Override
public void loaderAddText(SVGLoaderHelper helper, String text)
{
this.text.append(text);
//Invalidate style sheet
styleSheet = null;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("type")))
{
type = sty.getStringValue();
}
}
@Override
public boolean updateTime(double curTime) throws SVGException
{
//Style sheet doesn't change
return false;
}
public StyleSheet getStyleSheet()
{
if (styleSheet == null && text.length() > 0)
{
styleSheet = StyleSheet.parseSheet(text.toString());
}
return styleSheet;
}
}

View file

@ -0,0 +1,155 @@
/*
* 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 January 26, 2004, 1:56 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Symbol extends Group
{
public static final String TAG_NAME = "symbol";
AffineTransform viewXform;
Rectangle2D viewBox;
/**
* Creates a new instance of Stop
*/
public Symbol()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
// sty = getPres("unicode");
// if (sty != null) unicode = sty.getStringValue();
if (getPres(sty.setName("viewBox")))
{
float[] dim = sty.getFloatList();
viewBox = new Rectangle2D.Float(dim[0], dim[1], dim[2], dim[3]);
}
if (viewBox == null)
{
// viewBox = super.getBoundingBox();
viewBox = new Rectangle(0, 0, 1, 1);
}
//Transform pattern onto unit square
viewXform = new AffineTransform();
viewXform.scale(1.0 / viewBox.getWidth(), 1.0 / viewBox.getHeight());
viewXform.translate(-viewBox.getX(), -viewBox.getY());
}
@Override
protected boolean outsideClip(Graphics2D g) throws SVGException
{
Shape clip = g.getClip();
// g.getClipBounds(clipBounds);
Rectangle2D rect = super.getBoundingBox();
if (clip == null || clip.intersects(rect))
{
return false;
}
return true;
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
AffineTransform oldXform = g.getTransform();
g.transform(viewXform);
super.doRender(g);
g.setTransform(oldXform);
}
@Override
public Shape getShape()
{
Shape shape = super.getShape();
return viewXform.createTransformedShape(shape);
}
@Override
public Rectangle2D getBoundingBox() throws SVGException
{
Rectangle2D rect = super.getBoundingBox();
return viewXform.createTransformedShape(rect).getBounds2D();
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
boolean changeState = super.updateTime(curTime);
//View box properties do not change
return changeState;
}
}

View file

@ -0,0 +1,215 @@
/*
* 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 January 26, 2004, 1:56 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.util.FontUtil;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.util.Arrays;
import java.util.List;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Text extends Tspan
{
public static final String TAG_NAME = "text";
public static final int TXAN_START = 0;
public static final int TXAN_MIDDLE = 1;
public static final int TXAN_END = 2;
public static final int TXST_NORMAL = 0;
public static final int TXST_ITALIC = 1;
public static final int TXST_OBLIQUE = 2;
public static final int TXWE_NORMAL = 0;
public static final int TXWE_BOLD = 1;
public static final int TXWE_BOLDER = 2;
public static final int TXWE_LIGHTER = 3;
public static final int TXWE_100 = 4;
public static final int TXWE_200 = 5;
public static final int TXWE_300 = 6;
public static final int TXWE_400 = 7;
public static final int TXWE_500 = 8;
public static final int TXWE_600 = 9;
public static final int TXWE_700 = 10;
public static final int TXWE_800 = 11;
public static final int TXWE_900 = 12;
int textAnchor = TXAN_START;
/**
* Creates a new instance of Stop
*/
public Text()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Discard cached information
*/
public void rebuild() throws SVGException
{
build();
}
@Override
protected void build() throws SVGException
{
super.build();
buildText();
}
protected void buildAttributes(StyleAttribute sty) throws SVGException
{
super.buildAttributes(sty);
if (getStyle(sty.setName("text-anchor")))
{
String s = sty.getStringValue();
if (s.equals("middle"))
{
textAnchor = TXAN_MIDDLE;
} else if (s.equals("end"))
{
textAnchor = TXAN_END;
} else
{
textAnchor = TXAN_START;
}
} else
{
textAnchor = TXAN_START;
}
}
private void buildText() throws SVGException
{
Cursor cursor = createInitialCursor();
float xInitial = cursor.x;
super.buildTextShape(cursor);
alignSegmentsAtAnchor(fullPath, xInitial);
}
private void alignSegmentsAtAnchor(Path2D textPath, float xInitial)
{
AffineTransform tx;
Rectangle2D bounds;
switch (textAnchor)
{
case TXAN_MIDDLE:
bounds = textPath.getBounds2D();
tx = AffineTransform.getTranslateInstance(
-(bounds.getX() + bounds.getWidth() / 2.0 - xInitial), 0
);
break;
case TXAN_END:
bounds = textPath.getBounds2D();
tx = AffineTransform.getTranslateInstance(
-(bounds.getX() + bounds.getWidth() - xInitial), 0
);
break;
default:
tx = null;
break;
}
if (tx != null)
{
fullPath.transform(tx);
textBounds = fullPath.getBounds2D();
transformSegments(segments, tx);
}
}
private void transformSegments(List<TextSegment> segments, AffineTransform transform)
{
for (TextSegment segment : segments)
{
if (segment.textPath != null)
{
segment.textPath.transform(transform);
} else
{
segment.element.fullPath.transform(transform);
segment.element.textBounds = segment.element.fullPath.getBounds2D();
transformSegments(segment.element.segments, transform);
}
}
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
boolean changeState = super.updateTime(curTime);
//Get current values for parameters
FontUtil.FontInfo fontInfoOld = fontInfo;
float[] xOld = x;
float[] yOld = y;
float[] dxOld = dx;
float[] dyOld = dy;
buildShapeInformation();
boolean shapeChange = !fontInfo.equals(fontInfoOld)
|| !Arrays.equals(xOld, x)
|| !Arrays.equals(yOld, y)
|| !Arrays.equals(dxOld, dx)
|| !Arrays.equals(dyOld, dy);
if (shapeChange)
{
buildText();
}
return changeState || shapeChange;
}
}

View file

@ -0,0 +1,90 @@
/*
* 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 September 19, 2004, 1:56 AM
*/
package org.xbib.graphics.svg;
/**
* Holds title textual information within tree
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Title extends SVGElement
{
public static final String TAG_NAME = "title";
StringBuffer text = new StringBuffer();
/**
* Creates a new instance of Stop
*/
public Title()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Called during load process to add text scanned within a tag
*/
@Override
public void loaderAddText(SVGLoaderHelper helper, String text)
{
this.text.append(text);
}
public String getText()
{
return text.toString();
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
//Title does not change
return false;
}
}

View file

@ -0,0 +1,144 @@
/*
* 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 January 26, 2004, 9:00 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
/**
* Maintains bounding box for this element
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
abstract public class TransformableElement extends SVGElement
{
AffineTransform xform = null;
/**
* Creates a new instance of BoundedElement
*/
public TransformableElement()
{
}
public TransformableElement(String id, SVGElement parent)
{
super(id, parent);
}
/**
* Fetches a copy of the cached AffineTransform. Note that this value will
* only be valid after the node has been updated.
*
* @return
*/
public AffineTransform getXForm()
{
return xform == null ? null : new AffineTransform(xform);
}
/*
public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent)
{
//Load style string
super.loaderStartElement(helper, attrs, parent);
String transform = attrs.getValue("transform");
if (transform != null)
{
xform = parseTransform(transform);
}
}
*/
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("transform")))
{
xform = parseTransform(sty.getStringValue());
}
}
protected Shape shapeToParent(Shape shape)
{
if (xform == null)
{
return shape;
}
return xform.createTransformedShape(shape);
}
protected Rectangle2D boundsToParent(Rectangle2D rect)
{
if (xform == null || rect == null)
{
return rect;
}
return xform.createTransformedShape(rect).getBounds2D();
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("transform")))
{
AffineTransform newXform = parseTransform(sty.getStringValue());
if (!newXform.equals(xform))
{
xform = newXform;
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,395 @@
/*
* 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 January 26, 2004, 1:56 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.util.FontUtil;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Tspan extends ShapeElement
{
public static final String TAG_NAME = "tspan";
float[] x = null;
float[] y = null;
float[] dx = null;
float[] dy = null;
float[] rotate = null;
float textLength = -1;
String lengthAdjust = "spacing";
// List of strings and tspans containing the content of this node
private final List<Serializable> content = new ArrayList<>();
protected final ArrayList<TextSegment> segments = new ArrayList<>();
protected Rectangle2D textBounds;
protected Path2D fullPath;
protected FontUtil.FontInfo fontInfo;
private Font font;
/**
* Creates a new instance of Tspan
*/
public Tspan()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
/**
* Called after the start element but before the end element to indicate
* each child tag that has been processed
*/
@Override
public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
{
super.loaderAddChild(helper, child);
content.add(child);
}
/**
* Called during load process to add text scanned within a tag
*/
@Override
public void loaderAddText(SVGLoaderHelper helper, String text)
{
Matcher matchWs = Pattern.compile("\\s*").matcher(text);
if (!matchWs.matches())
{
content.add(text);
}
}
public List<Serializable> getContent()
{
return content;
}
/**
* Removes all strings and Tspan elements that are children of this element.
*/
public void clearContent()
{
content.clear();
}
public void appendText(String text)
{
content.add(text);
}
public void appendTspan(Tspan tspan) throws SVGElementException
{
super.loaderAddChild(null, tspan);
content.add(tspan);
}
protected void buildAttributes(StyleAttribute sty) throws SVGException
{
if (getPres(sty.setName("x")))
{
x = sty.getFloatListWithUnits();
}
if (getPres(sty.setName("y")))
{
y = sty.getFloatListWithUnits();
}
if (getPres(sty.setName("dx")))
{
dx = sty.getFloatListWithUnits();
}
if (getPres(sty.setName("dy")))
{
dy = sty.getFloatListWithUnits();
}
if (getPres(sty.setName("rotate")))
{
rotate = sty.getFloatList();
for (int i = 0; i < this.rotate.length; i++)
{
rotate[i] = (float) Math.toRadians(this.rotate[i]);
}
}
if (getStyle(sty.setName("textLength")))
{
textLength = sty.getFloatValueWithUnits();
}
else
{
textLength = -1;
}
if (getStyle(sty.setName("lengthAdjust")))
{
lengthAdjust = sty.getStringValue();
}
else
{
lengthAdjust = "spacing";
}
}
protected void buildShapeInformation() throws SVGException
{
StyleAttribute sty = new StyleAttribute();
buildAttributes(sty);
fontInfo = FontUtil.parseFontInfo(this, sty);
font = FontUtil.getFont(fontInfo, diagram);
}
protected void buildTextShape(Cursor cursor) throws SVGException
{
buildShapeInformation();
fullPath = new GeneralPath();
segments.clear();
segments.ensureCapacity(content.size());
int currentCursorOffset = cursor.offset;
cursor.offset = 0;
AffineTransform transform = new AffineTransform();
float spaceAdvance = font.getGlyph(" ").getHorizAdvX();
for (Serializable obj : content)
{
if (obj instanceof String)
{
String text = ((String) obj);
String trimmed = text.trim();
if (!text.isEmpty() && text.charAt(0) <= ' ')
cursor.x += font.getGlyph(" ").getHorizAdvX();
Path2D textPath = createStringSegmentPath(trimmed, font, cursor, transform);
if (!text.isEmpty() && text.charAt(text.length() - 1) <= ' ')
cursor.x += spaceAdvance;
fullPath.append(textPath, false);
segments.add(new TextSegment(textPath, this));
} else if (obj instanceof Tspan)
{
Tspan tspan = (Tspan) obj;
tspan.buildTextShape(cursor);
fullPath.append(tspan.fullPath, false);
segments.add(new TextSegment(null, (Tspan) obj));
}
}
textBounds = fullPath.getBounds2D();
cursor.offset += currentCursorOffset;
}
private Path2D createStringSegmentPath(String text, Font font, Cursor cursor, AffineTransform xform)
{
Path2D textPath = new GeneralPath();
for (int i = 0; i < text.length(); i++)
{
// The positions are specified for the whole recursive content of a span.
// We need to account for any eventual text which occurred before.
cursor.x = getXCursorForIndex(cursor.x, cursor.offset + i);
cursor.y = getYCursorForIndex(cursor.y, cursor.offset + i);
xform.setToTranslation(cursor.x, cursor.y);
if (rotate != null && cursor.offset + i < rotate.length)
{
xform.rotate(rotate[cursor.offset + i]);
}
String unicode = text.substring(i, i + 1);
MissingGlyph glyph = font.getGlyph(unicode);
Shape path = glyph.getPath();
if (path != null)
{
path = xform.createTransformedShape(path);
textPath.append(path, false);
}
cursor.x += glyph.getHorizAdvX() + fontInfo.letterSpacing;
}
cursor.offset += text.length();
strokeWidthScalar = 1f;
return textPath;
}
protected Cursor createInitialCursor()
{
return new Cursor(getXCursorForIndex(0, 0),
getYCursorForIndex(0, 0));
}
private float getXCursorForIndex(float current, int index)
{
return getCursorForIndex(current, index, x, dx);
}
private float getYCursorForIndex(float current, int index)
{
return getCursorForIndex(current, index, y, dy);
}
private float getCursorForIndex(float current, int index, float[] absolutes, float[] deltas)
{
if (absolutes != null && index < absolutes.length)
{
current = absolutes[index];
} else if (deltas != null && index < deltas.length)
{
current += deltas[index];
}
return current;
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
beginLayer(g);
for (TextSegment segment : segments) {
if (segment.textPath != null)
{
// Text portion of this span.
segment.element.renderShape(g, segment.textPath);
} else
{
// Child span.
segment.element.doRender(g);
}
}
finishLayer(g);
}
@Override
public Shape getShape()
{
return shapeToParent(fullPath);
}
@Override
public Rectangle2D getBoundingBox()
{
return boundsToParent(textBounds);
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
//Tspan does not change
return false;
}
public String getText()
{
return getText(new StringBuilder());
}
private String getText(StringBuilder builder)
{
for (Serializable serializable : content)
{
if (serializable instanceof Tspan)
{
((Tspan) serializable).getText(builder);
builder.append(' ');
} else if (serializable != null)
{
builder.append(serializable).append(' ');
}
}
if (builder.length() > 0)
{
// Remove trailing space.
return builder.substring(0, builder.length() - 1);
} else
{
return "";
}
}
protected static class TextSegment {
final Path2D textPath;
final Tspan element;
private TextSegment(Path2D textPath, Tspan element) {
this.textPath = textPath;
this.element = element;
}
}
protected static class Cursor {
float x;
float y;
int offset;
public Cursor(float x, float y) {
this.x = x;
this.y = y;
}
}
}

View file

@ -0,0 +1,264 @@
/*
* 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 January 26, 2004, 1:54 AM
*/
package org.xbib.graphics.svg;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.net.URI;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Use extends ShapeElement
{
public static final String TAG_NAME = "use";
float x = 0f;
float y = 0f;
float width = 1f;
float height = 1f;
// SVGElement href = null;
URI href = null;
AffineTransform refXform;
/**
* Creates a new instance of LinearGradient
*/
public Use()
{
}
@Override
public String getTagName()
{
return TAG_NAME;
}
@Override
protected void build() throws SVGException
{
super.build();
StyleAttribute sty = new StyleAttribute();
if (getPres(sty.setName("x")))
{
x = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("y")))
{
y = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("width")))
{
width = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("height")))
{
height = sty.getFloatValueWithUnits();
}
if (getPres(sty.setName("xlink:href")))
{
URI src = sty.getURIValue(getXMLBase());
href = src;
// href = diagram.getUniverse().getElement(src);
}
//Determine use offset/scale
refXform = new AffineTransform();
refXform.translate(this.x, this.y);
}
@Override
protected void doRender(Graphics2D g) throws SVGException
{
beginLayer(g);
//AffineTransform oldXform = g.getTransform();
AffineTransform oldXform = g.getTransform();
g.transform(refXform);
SVGElement ref = diagram.getUniverse().getElement(href);
if (ref == null || !(ref instanceof RenderableElement))
{
return;
}
RenderableElement rendEle = (RenderableElement)ref;
rendEle.pushParentContext(this);
rendEle.render(g);
rendEle.popParentContext();
g.setTransform(oldXform);
finishLayer(g);
}
@Override
public Shape getShape()
{
SVGElement ref = diagram.getUniverse().getElement(href);
if (ref instanceof ShapeElement)
{
Shape shape = ((ShapeElement) ref).getShape();
shape = refXform.createTransformedShape(shape);
shape = shapeToParent(shape);
return shape;
}
return null;
}
@Override
public Rectangle2D getBoundingBox() throws SVGException
{
SVGElement ref = diagram.getUniverse().getElement(href);
if (ref instanceof ShapeElement)
{
ShapeElement shapeEle = (ShapeElement) ref;
shapeEle.pushParentContext(this);
Rectangle2D bounds = shapeEle.getBoundingBox();
shapeEle.popParentContext();
bounds = refXform.createTransformedShape(bounds).getBounds2D();
bounds = boundsToParent(bounds);
return bounds;
}
return null;
}
/**
* Updates all attributes in this diagram associated with a time event. Ie,
* all attributes with track information.
*
* @return - true if this node has changed state as a result of the time
* update
*/
@Override
public boolean updateTime(double curTime) throws SVGException
{
// if (trackManager.getNumTracks() == 0) return false;
boolean changeState = super.updateTime(curTime);
//Get current values for parameters
StyleAttribute sty = new StyleAttribute();
boolean shapeChange = false;
if (getPres(sty.setName("x")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != x)
{
x = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("y")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != y)
{
y = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("width")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != width)
{
width = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("height")))
{
float newVal = sty.getFloatValueWithUnits();
if (newVal != height)
{
height = newVal;
shapeChange = true;
}
}
if (getPres(sty.setName("xlink:href")))
{
URI src = sty.getURIValue(getXMLBase());
// SVGElement newVal = diagram.getUniverse().getElement(src);
if (!src.equals(href))
{
href = src;
shapeChange = true;
}
}
/*
if (getPres(sty.setName("xlink:href")))
{
URI src = sty.getURIValue(getXMLBase());
href = diagram.getUniverse().getElement(src);
}
//Determine use offset/scale
refXform = new AffineTransform();
refXform.translate(this.x, this.y);
refXform.scale(this.width, this.height);
*/
if (shapeChange)
{
build();
//Determine use offset/scale
// refXform.setToTranslation(this.x, this.y);
// refXform.scale(this.width, this.height);
// return true;
}
return changeState || shapeChange;
}
}

View file

@ -0,0 +1,165 @@
/*
* 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 September 6, 2004, 1:19 AM
*/
package org.xbib.graphics.svg.app;
/**
*
* @author kitfox
*/
public class MainFrame extends javax.swing.JFrame
{
public static final long serialVersionUID = 1;
/** Creates new form MainFrame */
public MainFrame()
{
initComponents();
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
private void initComponents()//GEN-BEGIN:initComponents
{
jPanel1 = new javax.swing.JPanel();
bn_svgViewer = new javax.swing.JButton();
bn_svgViewer1 = new javax.swing.JButton();
jPanel2 = new javax.swing.JPanel();
bn_quit = new javax.swing.JButton();
setTitle("SVG Salamander - Application Launcher");
addWindowListener(new java.awt.event.WindowAdapter()
{
@Override
public void windowClosing(java.awt.event.WindowEvent evt)
{
exitForm(evt);
}
});
jPanel1.setLayout(new javax.swing.BoxLayout(jPanel1, javax.swing.BoxLayout.Y_AXIS));
bn_svgViewer.setText("SVG Viewer (No animation)");
bn_svgViewer.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
bn_svgViewerActionPerformed(evt);
}
});
jPanel1.add(bn_svgViewer);
bn_svgViewer1.setText("SVG Player (Animation)");
bn_svgViewer1.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
bn_svgViewer1ActionPerformed(evt);
}
});
jPanel1.add(bn_svgViewer1);
getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER);
bn_quit.setText("Quit");
bn_quit.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
bn_quitActionPerformed(evt);
}
});
jPanel2.add(bn_quit);
getContentPane().add(jPanel2, java.awt.BorderLayout.SOUTH);
pack();
}//GEN-END:initComponents
private void bn_svgViewer1ActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_svgViewer1ActionPerformed
{//GEN-HEADEREND:event_bn_svgViewer1ActionPerformed
SVGPlayer.main(null);
close();
}//GEN-LAST:event_bn_svgViewer1ActionPerformed
private void bn_svgViewerActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_svgViewerActionPerformed
{//GEN-HEADEREND:event_bn_svgViewerActionPerformed
SVGViewer.main(null);
close();
}//GEN-LAST:event_bn_svgViewerActionPerformed
private void bn_quitActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_quitActionPerformed
{//GEN-HEADEREND:event_bn_quitActionPerformed
exitForm(null);
}//GEN-LAST:event_bn_quitActionPerformed
/** Exit the Application */
private void exitForm(java.awt.event.WindowEvent evt)//GEN-FIRST:event_exitForm
{
System.exit(0);
}//GEN-LAST:event_exitForm
private void close()
{
this.setVisible(false);
this.dispose();
}
/**
* @param args the command line arguments
*/
public static void main(String args[])
{
new MainFrame().setVisible(true);
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton bn_quit;
private javax.swing.JButton bn_svgViewer;
private javax.swing.JButton bn_svgViewer1;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
// End of variables declaration//GEN-END:variables
}

View file

@ -0,0 +1,301 @@
/*
* 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 September 28, 2004, 9:56 PM
*/
package org.xbib.graphics.svg.app;
/**
*
* @author kitfox
*/
public class PlayerDialog extends javax.swing.JDialog implements PlayerThreadListener
{
public static final long serialVersionUID = 1;
PlayerThread thread;
final SVGPlayer parent;
/** Creates new form PlayerDialog */
public PlayerDialog(SVGPlayer parent)
{
super(parent, false);
initComponents();
this.parent = parent;
thread = new PlayerThread();
thread.addListener(this);
text_timeStepActionPerformed(null);
}
public void updateTime(double curTime, double timeStep, int playState)
{
if (playState == PlayerThread.PS_STOP) return;
text_curTime.setText("" + (float)curTime);
parent.updateTime(curTime);
// text_timeStep.setText("" + (int)(1.0 / timeStep));
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
private void initComponents()
{
jPanel1 = new javax.swing.JPanel();
bn_playBack = new javax.swing.JButton();
bn_stop = new javax.swing.JButton();
bn_playFwd = new javax.swing.JButton();
jPanel2 = new javax.swing.JPanel();
jPanel3 = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
text_curTime = new javax.swing.JTextField();
bn_time0 = new javax.swing.JButton();
jPanel4 = new javax.swing.JPanel();
jLabel2 = new javax.swing.JLabel();
text_timeStep = new javax.swing.JTextField();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("Player");
addWindowListener(new java.awt.event.WindowAdapter()
{
@Override
public void windowClosed(java.awt.event.WindowEvent evt)
{
formWindowClosed(evt);
}
});
bn_playBack.setText("<");
bn_playBack.setToolTipText("Play backwards");
bn_playBack.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
bn_playBackActionPerformed(evt);
}
});
jPanel1.add(bn_playBack);
bn_stop.setText("||");
bn_stop.setToolTipText("Stop playback");
bn_stop.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
bn_stopActionPerformed(evt);
}
});
jPanel1.add(bn_stop);
bn_playFwd.setText(">");
bn_playFwd.setToolTipText("Play Forwards");
bn_playFwd.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
bn_playFwdActionPerformed(evt);
}
});
jPanel1.add(bn_playFwd);
getContentPane().add(jPanel1, java.awt.BorderLayout.NORTH);
jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, javax.swing.BoxLayout.Y_AXIS));
jLabel1.setText("Cur Time");
jPanel3.add(jLabel1);
text_curTime.setHorizontalAlignment(javax.swing.JTextField.LEFT);
text_curTime.setText("0");
text_curTime.setPreferredSize(new java.awt.Dimension(100, 21));
text_curTime.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
text_curTimeActionPerformed(evt);
}
});
text_curTime.addFocusListener(new java.awt.event.FocusAdapter()
{
@Override
public void focusLost(java.awt.event.FocusEvent evt)
{
text_curTimeFocusLost(evt);
}
});
jPanel3.add(text_curTime);
bn_time0.setText("Time 0");
bn_time0.setToolTipText("Reset time to first frame");
bn_time0.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
bn_time0ActionPerformed(evt);
}
});
jPanel3.add(bn_time0);
jPanel2.add(jPanel3);
jLabel2.setText("Frames Per Second");
jPanel4.add(jLabel2);
text_timeStep.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
text_timeStep.setText("60");
text_timeStep.setPreferredSize(new java.awt.Dimension(100, 21));
text_timeStep.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
text_timeStepActionPerformed(evt);
}
});
text_timeStep.addFocusListener(new java.awt.event.FocusAdapter()
{
@Override
public void focusLost(java.awt.event.FocusEvent evt)
{
text_timeStepFocusLost(evt);
}
});
jPanel4.add(text_timeStep);
jPanel2.add(jPanel4);
getContentPane().add(jPanel2, java.awt.BorderLayout.CENTER);
pack();
}// </editor-fold>//GEN-END:initComponents
private void bn_time0ActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_time0ActionPerformed
{//GEN-HEADEREND:event_bn_time0ActionPerformed
thread.setCurTime(0);
}//GEN-LAST:event_bn_time0ActionPerformed
private void bn_playFwdActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_playFwdActionPerformed
{//GEN-HEADEREND:event_bn_playFwdActionPerformed
thread.setPlayState(PlayerThread.PS_PLAY_FWD);
}//GEN-LAST:event_bn_playFwdActionPerformed
private void bn_stopActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_stopActionPerformed
{//GEN-HEADEREND:event_bn_stopActionPerformed
thread.setPlayState(PlayerThread.PS_STOP);
}//GEN-LAST:event_bn_stopActionPerformed
private void bn_playBackActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_playBackActionPerformed
{//GEN-HEADEREND:event_bn_playBackActionPerformed
thread.setPlayState(PlayerThread.PS_PLAY_BACK);
}//GEN-LAST:event_bn_playBackActionPerformed
private void formWindowClosed(java.awt.event.WindowEvent evt)//GEN-FIRST:event_formWindowClosed
{//GEN-HEADEREND:event_formWindowClosed
// thread.exit();
}//GEN-LAST:event_formWindowClosed
private void text_timeStepFocusLost(java.awt.event.FocusEvent evt)//GEN-FIRST:event_text_timeStepFocusLost
{//GEN-HEADEREND:event_text_timeStepFocusLost
text_timeStepActionPerformed(null);
}//GEN-LAST:event_text_timeStepFocusLost
private void text_timeStepActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_text_timeStepActionPerformed
{//GEN-HEADEREND:event_text_timeStepActionPerformed
try
{
int val = Integer.parseInt(text_timeStep.getText());
thread.setTimeStep(1.0 / val);
}
catch (Exception e)
{
}
double d = thread.getTimeStep();
String newStrn = "" + (int)(1f / d);
if (newStrn.equals(text_timeStep.getText())) return;
text_timeStep.setText(newStrn);
// text_timeStepActionPerformed(null);
}//GEN-LAST:event_text_timeStepActionPerformed
private void text_curTimeActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_text_curTimeActionPerformed
{//GEN-HEADEREND:event_text_curTimeActionPerformed
try
{
double val = Double.parseDouble(text_curTime.getText());
thread.setCurTime(val);
}
catch (Exception e)
{
}
double d = thread.getCurTime();
text_curTime.setText("" + (float)d);
text_timeStepActionPerformed(null);
}//GEN-LAST:event_text_curTimeActionPerformed
private void text_curTimeFocusLost(java.awt.event.FocusEvent evt)//GEN-FIRST:event_text_curTimeFocusLost
{//GEN-HEADEREND:event_text_curTimeFocusLost
text_curTimeActionPerformed(null);
}//GEN-LAST:event_text_curTimeFocusLost
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton bn_playBack;
private javax.swing.JButton bn_playFwd;
private javax.swing.JButton bn_stop;
private javax.swing.JButton bn_time0;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JPanel jPanel3;
private javax.swing.JPanel jPanel4;
private javax.swing.JTextField text_curTime;
private javax.swing.JTextField text_timeStep;
// End of variables declaration//GEN-END:variables
}

View file

@ -0,0 +1,136 @@
/*
* 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 September 28, 2004, 10:07 PM
*/
package org.xbib.graphics.svg.app;
import java.util.*;
/**
*
* @author kitfox
*/
public class PlayerThread implements Runnable
{
HashSet<PlayerThreadListener> listeners = new HashSet<PlayerThreadListener>();
double curTime = 0;
double timeStep = .2;
public static final int PS_STOP = 0;
public static final int PS_PLAY_FWD = 1;
public static final int PS_PLAY_BACK = 2;
int playState = PS_STOP;
Thread thread;
/** Creates a new instance of PlayerThread */
public PlayerThread()
{
thread = new Thread(this);
thread.start();
}
public void run()
{
while (thread != null)
{
synchronized (this)
{
switch (playState)
{
case PS_PLAY_FWD:
curTime += timeStep;
break;
case PS_PLAY_BACK:
curTime -= timeStep;
if (curTime < 0) curTime = 0;
break;
default:
case PS_STOP:
break;
}
fireTimeUpdateEvent();
}
try
{
Thread.sleep((long)(timeStep * 1000));
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
public void exit() { thread = null; }
public synchronized void addListener(PlayerThreadListener listener)
{
listeners.add(listener);
}
public synchronized double getCurTime() { return curTime; }
public synchronized void setCurTime(double time)
{
curTime = time;
}
public synchronized double getTimeStep() { return timeStep; }
public synchronized void setTimeStep(double time)
{
timeStep = time;
if (timeStep < .01) timeStep = .01;
}
public synchronized int getPlayState() { return playState; }
public synchronized void setPlayState(int playState)
{
this.playState = playState;
}
private void fireTimeUpdateEvent()
{
for (PlayerThreadListener listener : listeners) {
listener.updateTime(curTime, timeStep, playState);
}
}
}

View file

@ -0,0 +1,46 @@
/*
* 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 September 28, 2004, 10:15 PM
*/
package org.xbib.graphics.svg.app;
/**
*
* @author kitfox
*/
public interface PlayerThreadListener
{
public void updateTime(double curTime, double timeStep, int playState);
}

View file

@ -0,0 +1,450 @@
/*
* 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 3, 2004, 5:28 PM
*/
package org.xbib.graphics.svg.app;
import org.xbib.graphics.svg.SVGConst;
import org.xbib.graphics.svg.SVGDiagram;
import org.xbib.graphics.svg.SVGDisplayPanel;
import org.xbib.graphics.svg.SVGElement;
import org.xbib.graphics.svg.SVGException;
import org.xbib.graphics.svg.SVGUniverse;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.io.File;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.security.AccessControlException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class SVGPlayer extends javax.swing.JFrame
{
public static final long serialVersionUID = 1;
SVGDisplayPanel svgDisplayPanel = new SVGDisplayPanel();
final PlayerDialog playerDialog;
SVGUniverse universe;
/** FileChooser for running in trusted environments */
final JFileChooser fileChooser;
{
// fileChooser = new JFileChooser(new File("."));
JFileChooser fc = null;
try
{
fc = new JFileChooser();
fc.setFileFilter(
new javax.swing.filechooser.FileFilter() {
final Matcher matchLevelFile = Pattern.compile(".*\\.svg[z]?").matcher("");
@Override
public boolean accept(File file)
{
if (file.isDirectory()) return true;
matchLevelFile.reset(file.getName());
return matchLevelFile.matches();
}
@Override
public String getDescription() { return "SVG file (*.svg, *.svgz)"; }
}
);
}
catch (AccessControlException ex)
{
//Do not create file chooser if webstart refuses permissions
}
fileChooser = fc;
}
/** Backup file service for opening files in WebStart situations */
/*
final FileOpenService fileOpenService;
{
try
{
fileOpenService = (FileOpenService)ServiceManager.lookup("javax.jnlp.FileOpenService");
}
catch (UnavailableServiceException e)
{
fileOpenService = null;
}
}
*/
/** Creates new form SVGViewer */
public SVGPlayer() {
initComponents();
setSize(800, 600);
svgDisplayPanel.setBgColor(Color.white);
svgDisplayPanel.addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent evt)
{
SVGDiagram diagram = svgDisplayPanel.getDiagram();
if (diagram == null) return;
System.out.println("Picking at cursor (" + evt.getX() + ", " + evt.getY() + ")");
try
{
List<List<SVGElement>> paths = diagram.pick(new Point2D.Float(evt.getX(), evt.getY()), null);
for (int i = 0; i < paths.size(); i++)
{
System.out.println(pathToString(paths.get(i)));
}
}
catch (SVGException ex)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING,
"Could not pick", ex);
}
}
}
);
svgDisplayPanel.setPreferredSize(getSize());
scrollPane_svgArea.setViewportView(svgDisplayPanel);
playerDialog = new PlayerDialog(this);
}
private String pathToString(List<SVGElement> path)
{
if (path.size() == 0) return "";
StringBuffer sb = new StringBuffer();
sb.append(path.get(0));
for (int i = 1; i < path.size(); i++)
{
sb.append("/");
sb.append(path.get(i).getId());
}
return sb.toString();
}
public void updateTime(double curTime)
{
try
{
if (universe != null)
{
universe.setCurTime(curTime);
universe.updateTime();
// svgDisplayPanel.updateTime(curTime);
repaint();
}
}
catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
}
}
private void loadURL(URL url)
{
boolean verbose = cmCheck_verbose.isSelected();
universe = new SVGUniverse();
universe.setVerbose(verbose);
SVGDiagram diagram = null;
if (!CheckBoxMenuItem_anonInputStream.isSelected())
{
//Load from a disk with a valid URL
URI uri = universe.loadSVG(url);
if (verbose) System.err.println(uri.toString());
diagram = universe.getDiagram(uri);
}
else
{
//Load from a stream with no particular valid URL
try
{
InputStream is = url.openStream();
URI uri = universe.loadSVG(is, "defaultName");
if (verbose) System.err.println(uri.toString());
diagram = universe.getDiagram(uri);
}
catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
}
}
svgDisplayPanel.setDiagram(diagram);
repaint();
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
private void initComponents()
{
scrollPane_svgArea = new javax.swing.JScrollPane();
jMenuBar1 = new javax.swing.JMenuBar();
menu_file = new javax.swing.JMenu();
cm_loadFile = new javax.swing.JMenuItem();
cm_loadUrl = new javax.swing.JMenuItem();
menu_window = new javax.swing.JMenu();
cm_player = new javax.swing.JMenuItem();
jSeparator2 = new javax.swing.JSeparator();
cm_800x600 = new javax.swing.JMenuItem();
CheckBoxMenuItem_anonInputStream = new javax.swing.JCheckBoxMenuItem();
cmCheck_verbose = new javax.swing.JCheckBoxMenuItem();
menu_help = new javax.swing.JMenu();
cm_about = new javax.swing.JMenuItem();
setTitle("SVG Player - Salamander Project");
addWindowListener(new java.awt.event.WindowAdapter()
{
@Override
public void windowClosing(java.awt.event.WindowEvent evt)
{
exitForm(evt);
}
});
getContentPane().add(scrollPane_svgArea, java.awt.BorderLayout.CENTER);
menu_file.setMnemonic('f');
menu_file.setText("File");
cm_loadFile.setMnemonic('l');
cm_loadFile.setText("Load File...");
cm_loadFile.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
cm_loadFileActionPerformed(evt);
}
});
menu_file.add(cm_loadFile);
cm_loadUrl.setText("Load URL...");
cm_loadUrl.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
cm_loadUrlActionPerformed(evt);
}
});
menu_file.add(cm_loadUrl);
jMenuBar1.add(menu_file);
menu_window.setText("Window");
cm_player.setText("Player");
cm_player.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
cm_playerActionPerformed(evt);
}
});
menu_window.add(cm_player);
menu_window.add(jSeparator2);
cm_800x600.setText("800 x 600");
cm_800x600.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
cm_800x600ActionPerformed(evt);
}
});
menu_window.add(cm_800x600);
CheckBoxMenuItem_anonInputStream.setText("Anonymous Input Stream");
menu_window.add(CheckBoxMenuItem_anonInputStream);
cmCheck_verbose.setText("Verbose");
cmCheck_verbose.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
cmCheck_verboseActionPerformed(evt);
}
});
menu_window.add(cmCheck_verbose);
jMenuBar1.add(menu_window);
menu_help.setText("Help");
cm_about.setText("About...");
cm_about.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
cm_aboutActionPerformed(evt);
}
});
menu_help.add(cm_about);
jMenuBar1.add(menu_help);
setJMenuBar(jMenuBar1);
pack();
}// </editor-fold>//GEN-END:initComponents
private void cm_loadUrlActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_loadUrlActionPerformed
{//GEN-HEADEREND:event_cm_loadUrlActionPerformed
String urlStrn = JOptionPane.showInputDialog(this, "Enter URL of SVG file");
if (urlStrn == null) return;
try
{
URL url = new URL(URLEncoder.encode(urlStrn, "UTF-8"));
loadURL(url);
}
catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
}
}//GEN-LAST:event_cm_loadUrlActionPerformed
private void cmCheck_verboseActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cmCheck_verboseActionPerformed
{//GEN-HEADEREND:event_cmCheck_verboseActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_cmCheck_verboseActionPerformed
private void cm_playerActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_playerActionPerformed
{//GEN-HEADEREND:event_cm_playerActionPerformed
playerDialog.setVisible(true);
}//GEN-LAST:event_cm_playerActionPerformed
private void cm_aboutActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_aboutActionPerformed
{//GEN-HEADEREND:event_cm_aboutActionPerformed
VersionDialog dia = new VersionDialog(this, true, cmCheck_verbose.isSelected());
dia.setVisible(true);
// JOptionPane.showMessageDialog(this, "Salamander SVG - Created by Mark McKay\nhttp://www.kitfox.com");
}//GEN-LAST:event_cm_aboutActionPerformed
private void cm_800x600ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cm_800x600ActionPerformed
setSize(800, 600);
}//GEN-LAST:event_cm_800x600ActionPerformed
private void cm_loadFileActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_loadFileActionPerformed
{//GEN-HEADEREND:event_cm_loadFileActionPerformed
boolean verbose = cmCheck_verbose.isSelected();
try
{
int retVal = fileChooser.showOpenDialog(this);
if (retVal == JFileChooser.APPROVE_OPTION)
{
File chosenFile = fileChooser.getSelectedFile();
URL url = chosenFile.toURI().toURL();
loadURL(url);
}
}
catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
}
}//GEN-LAST:event_cm_loadFileActionPerformed
/** Exit the Application */
private void exitForm(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_exitForm
System.exit(0);
}//GEN-LAST:event_exitForm
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
new SVGPlayer().setVisible(true);
}
public void updateTime(double curTime, double timeStep, int playState)
{
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBoxMenuItem CheckBoxMenuItem_anonInputStream;
private javax.swing.JCheckBoxMenuItem cmCheck_verbose;
private javax.swing.JMenuItem cm_800x600;
private javax.swing.JMenuItem cm_about;
private javax.swing.JMenuItem cm_loadFile;
private javax.swing.JMenuItem cm_loadUrl;
private javax.swing.JMenuItem cm_player;
private javax.swing.JMenuBar jMenuBar1;
private javax.swing.JSeparator jSeparator2;
private javax.swing.JMenu menu_file;
private javax.swing.JMenu menu_help;
private javax.swing.JMenu menu_window;
private javax.swing.JScrollPane scrollPane_svgArea;
// End of variables declaration//GEN-END:variables
}

View file

@ -0,0 +1,425 @@
/*
* 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 3, 2004, 5:28 PM
*/
package org.xbib.graphics.svg.app;
import org.xbib.graphics.svg.SVGCache;
import org.xbib.graphics.svg.SVGConst;
import org.xbib.graphics.svg.SVGDiagram;
import org.xbib.graphics.svg.SVGDisplayPanel;
import org.xbib.graphics.svg.SVGElement;
import org.xbib.graphics.svg.SVGException;
import org.xbib.graphics.svg.SVGUniverse;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Point;
import java.io.File;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.security.AccessControlException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class SVGViewer extends javax.swing.JFrame
{
public static final long serialVersionUID = 1;
SVGDisplayPanel svgDisplayPanel = new SVGDisplayPanel();
/** FileChooser for running in trusted environments */
final JFileChooser fileChooser;
{
// fileChooser = new JFileChooser(new File("."));
JFileChooser fc = null;
try
{
fc = new JFileChooser();
fc.setFileFilter(
new javax.swing.filechooser.FileFilter() {
final Matcher matchLevelFile = Pattern.compile(".*\\.svg[z]?").matcher("");
@Override
public boolean accept(File file)
{
if (file.isDirectory()) return true;
matchLevelFile.reset(file.getName());
return matchLevelFile.matches();
}
@Override
public String getDescription() { return "SVG file (*.svg, *.svgz)"; }
}
);
}
catch (AccessControlException ex)
{
//Do not create file chooser if webstart refuses permissions
}
fileChooser = fc;
}
/** Backup file service for opening files in WebStart situations */
/*
final FileOpenService fileOpenService;
{
try
{
fileOpenService = (FileOpenService)ServiceManager.lookup("javax.jnlp.FileOpenService");
}
catch (UnavailableServiceException e)
{
fileOpenService = null;
}
}
*/
/** Creates new form SVGViewer */
public SVGViewer() {
initComponents();
setSize(800, 600);
svgDisplayPanel.setBgColor(Color.white);
svgDisplayPanel.setPreferredSize(getSize());
panel_svgArea.add(svgDisplayPanel, BorderLayout.CENTER);
// scrollPane_svgArea.setViewportView(svgDisplayPanel);
}
private void loadURL(URL url)
{
boolean verbose = cmCheck_verbose.isSelected();
// SVGUniverse universe = new SVGUniverse();
SVGUniverse universe = SVGCache.getSVGUniverse();
SVGDiagram diagram = null;
URI uri;
if (!CheckBoxMenuItem_anonInputStream.isSelected())
{
//Load from a disk with a valid URL
uri = universe.loadSVG(url);
if (verbose) System.err.println("Loading document " + uri.toString());
diagram = universe.getDiagram(uri);
}
else
{
//Load from a stream with no particular valid URL
try
{
InputStream is = url.openStream();
uri = universe.loadSVG(is, "defaultName");
if (verbose) System.err.println("Loading document " + uri.toString());
}
catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
return;
}
}
/*
ByteArrayOutputStream bs = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bs);
os.writeObject(universe);
os.close();
ByteArrayInputStream bin = new ByteArrayInputStream(bs.toByteArray());
ObjectInputStream is = new ObjectInputStream(bin);
universe = (SVGUniverse)is.readObject();
is.close();
*/
diagram = universe.getDiagram(uri);
svgDisplayPanel.setDiagram(diagram);
repaint();
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
private void initComponents()
{
scrollPane_svgArea = new javax.swing.JScrollPane();
panel_svgArea = new javax.swing.JPanel();
jMenuBar1 = new javax.swing.JMenuBar();
menu_file = new javax.swing.JMenu();
cm_loadFile = new javax.swing.JMenuItem();
cm_loadUrl = new javax.swing.JMenuItem();
menu_window = new javax.swing.JMenu();
cm_800x600 = new javax.swing.JMenuItem();
CheckBoxMenuItem_anonInputStream = new javax.swing.JCheckBoxMenuItem();
cmCheck_verbose = new javax.swing.JCheckBoxMenuItem();
menu_help = new javax.swing.JMenu();
cm_about = new javax.swing.JMenuItem();
setTitle("SVG Viewer - Salamander Project");
addWindowListener(new java.awt.event.WindowAdapter()
{
@Override
public void windowClosing(java.awt.event.WindowEvent evt)
{
exitForm(evt);
}
});
panel_svgArea.setLayout(new java.awt.BorderLayout());
panel_svgArea.addMouseListener(new java.awt.event.MouseAdapter()
{
@Override
public void mousePressed(java.awt.event.MouseEvent evt)
{
panel_svgAreaMousePressed(evt);
}
@Override
public void mouseReleased(java.awt.event.MouseEvent evt)
{
panel_svgAreaMouseReleased(evt);
}
});
scrollPane_svgArea.setViewportView(panel_svgArea);
getContentPane().add(scrollPane_svgArea, java.awt.BorderLayout.CENTER);
menu_file.setMnemonic('f');
menu_file.setText("File");
cm_loadFile.setMnemonic('l');
cm_loadFile.setText("Load File...");
cm_loadFile.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
cm_loadFileActionPerformed(evt);
}
});
menu_file.add(cm_loadFile);
cm_loadUrl.setText("Load URL...");
cm_loadUrl.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
cm_loadUrlActionPerformed(evt);
}
});
menu_file.add(cm_loadUrl);
jMenuBar1.add(menu_file);
menu_window.setText("Window");
cm_800x600.setText("800 x 600");
cm_800x600.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
cm_800x600ActionPerformed(evt);
}
});
menu_window.add(cm_800x600);
CheckBoxMenuItem_anonInputStream.setText("Anonymous Input Stream");
menu_window.add(CheckBoxMenuItem_anonInputStream);
cmCheck_verbose.setText("Verbose");
cmCheck_verbose.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
cmCheck_verboseActionPerformed(evt);
}
});
menu_window.add(cmCheck_verbose);
jMenuBar1.add(menu_window);
menu_help.setText("Help");
cm_about.setText("About...");
cm_about.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
cm_aboutActionPerformed(evt);
}
});
menu_help.add(cm_about);
jMenuBar1.add(menu_help);
setJMenuBar(jMenuBar1);
pack();
}// </editor-fold>//GEN-END:initComponents
private void cm_loadUrlActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_loadUrlActionPerformed
{//GEN-HEADEREND:event_cm_loadUrlActionPerformed
String urlStrn = JOptionPane.showInputDialog(this, "Enter URL of SVG file");
if (urlStrn == null) return;
try
{
URL url = new URL(URLEncoder.encode(urlStrn, "UTF-8"));
loadURL(url);
}
catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
}
}//GEN-LAST:event_cm_loadUrlActionPerformed
private void panel_svgAreaMouseReleased(java.awt.event.MouseEvent evt)//GEN-FIRST:event_panel_svgAreaMouseReleased
{//GEN-HEADEREND:event_panel_svgAreaMouseReleased
SVGDiagram diagram = svgDisplayPanel.getDiagram();
List<List<SVGElement>> pickedElements;
try
{
pickedElements = diagram.pick(new Point(evt.getX(), evt.getY()), null);
}
catch (SVGException e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
return;
}
System.out.println("Pick results:");
for (List<SVGElement> path : pickedElements) {
System.out.print(" Path: ");
for (SVGElement ele : path) {
System.out.print("" + ele.getId() + "(" + ele.getClass().getName() + ") ");
}
System.out.println();
}
}//GEN-LAST:event_panel_svgAreaMouseReleased
private void panel_svgAreaMousePressed(java.awt.event.MouseEvent evt)//GEN-FIRST:event_panel_svgAreaMousePressed
{//GEN-HEADEREND:event_panel_svgAreaMousePressed
}//GEN-LAST:event_panel_svgAreaMousePressed
private void cmCheck_verboseActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cmCheck_verboseActionPerformed
{//GEN-HEADEREND:event_cmCheck_verboseActionPerformed
SVGCache.getSVGUniverse().setVerbose(cmCheck_verbose.isSelected());
}//GEN-LAST:event_cmCheck_verboseActionPerformed
private void cm_aboutActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_aboutActionPerformed
{//GEN-HEADEREND:event_cm_aboutActionPerformed
//JOptionPane.showMessageDialog(this, "Salamander SVG - Created by Mark McKay\nhttp://www.kitfox.com");
VersionDialog dlg = new VersionDialog(this, true, cmCheck_verbose.isSelected());
dlg.setVisible(true);
}//GEN-LAST:event_cm_aboutActionPerformed
private void cm_800x600ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cm_800x600ActionPerformed
setSize(800, 600);
}//GEN-LAST:event_cm_800x600ActionPerformed
private void cm_loadFileActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_cm_loadFileActionPerformed
{//GEN-HEADEREND:event_cm_loadFileActionPerformed
try
{
int retVal = fileChooser.showOpenDialog(this);
if (retVal == JFileChooser.APPROVE_OPTION)
{
File chosenFile = fileChooser.getSelectedFile();
URL url = chosenFile.toURI().toURL();
loadURL(url);
}
}
catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
}
}//GEN-LAST:event_cm_loadFileActionPerformed
/** Exit the Application */
private void exitForm(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_exitForm
// setVisible(false);
// dispose();
System.exit(0);
}//GEN-LAST:event_exitForm
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
new SVGViewer().setVisible(true);
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBoxMenuItem CheckBoxMenuItem_anonInputStream;
private javax.swing.JCheckBoxMenuItem cmCheck_verbose;
private javax.swing.JMenuItem cm_800x600;
private javax.swing.JMenuItem cm_about;
private javax.swing.JMenuItem cm_loadFile;
private javax.swing.JMenuItem cm_loadUrl;
private javax.swing.JMenuBar jMenuBar1;
private javax.swing.JMenu menu_file;
private javax.swing.JMenu menu_help;
private javax.swing.JMenu menu_window;
private javax.swing.JPanel panel_svgArea;
private javax.swing.JScrollPane scrollPane_svgArea;
// End of variables declaration//GEN-END:variables
}

View file

@ -0,0 +1,158 @@
/*
* 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 January 13, 2005, 7:23 AM
*/
package org.xbib.graphics.svg.app;
import org.xbib.graphics.svg.SVGConst;
import java.net.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author kitfox
*/
public class VersionDialog extends javax.swing.JDialog
{
public static final long serialVersionUID = 1;
final boolean verbose;
/** Creates new form VersionDialog */
public VersionDialog(java.awt.Frame parent, boolean modal, boolean verbose)
{
super(parent, modal);
initComponents();
this.verbose = verbose;
textpane_text.setContentType("text/html");
StringBuffer sb = new StringBuffer();
try
{
URL url = getClass().getResource("/res/help/about/about.html");
if (verbose)
{
System.err.println("" + getClass() + " trying to load about html " + url);
}
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
while (true)
{
String line = reader.readLine();
if (line == null) break;
sb.append(line);
}
textpane_text.setText(sb.toString());
}
catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
}
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
private void initComponents()
{
jPanel1 = new javax.swing.JPanel();
textpane_text = new javax.swing.JTextPane();
jPanel2 = new javax.swing.JPanel();
bn_close = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("About SVG Salamander");
jPanel1.setLayout(new java.awt.BorderLayout());
textpane_text.setEditable(false);
textpane_text.setPreferredSize(new java.awt.Dimension(400, 300));
jPanel1.add(textpane_text, java.awt.BorderLayout.CENTER);
getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER);
bn_close.setText("Close");
bn_close.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
bn_closeActionPerformed(evt);
}
});
jPanel2.add(bn_close);
getContentPane().add(jPanel2, java.awt.BorderLayout.SOUTH);
pack();
}
// </editor-fold>//GEN-END:initComponents
private void bn_closeActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_bn_closeActionPerformed
{//GEN-HEADEREND:event_bn_closeActionPerformed
setVisible(false);
dispose();
}//GEN-LAST:event_bn_closeActionPerformed
/**
* @param args the command line arguments
*/
public static void main(String args[])
{
java.awt.EventQueue.invokeLater(new Runnable()
{
public void run()
{
new VersionDialog(new javax.swing.JFrame(), true, true).setVisible(true);
}
});
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton bn_close;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JTextPane textpane_text;
// End of variables declaration//GEN-END:variables
}

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.2" maxVersion="1.2" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Events>
<EventHandler event="componentResized" listener="java.awt.event.ComponentListener" parameters="java.awt.event.ComponentEvent" handler="formComponentResized"/>
<EventHandler event="componentShown" listener="java.awt.event.ComponentListener" parameters="java.awt.event.ComponentEvent" handler="formComponentShown"/>
</Events>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
<Property name="useNullLayout" type="boolean" value="true"/>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="jPanel1">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout" value="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout$AbsoluteConstraintsDescription">
<AbsoluteConstraints x="80" y="90" width="280" height="160"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
</SubComponents>
</Form>

View file

@ -0,0 +1,123 @@
/*
* 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 May 7, 2005, 4:15 AM
*/
package org.xbib.graphics.svg.app.beans;
import java.awt.*;
import javax.swing.*;
/**
* Panel based on the null layout. Allows editing with absolute layout. When
* instanced, records layout dimensions of all subcomponents. Then, if the
* panel is ever resized, scales all children to fit new size.
*
* @author kitfox
*/
public class ProportionalLayoutPanel extends javax.swing.JPanel
{
public static final long serialVersionUID = 1;
//Margins to leave on sides of panel, expressed in fractions [0 1]
float topMargin;
float bottomMargin;
float leftMargin;
float rightMargin;
/** Creates new form ProportionalLayoutPanel */
public ProportionalLayoutPanel()
{
initComponents();
}
@Override
public void addNotify()
{
super.addNotify();
Rectangle rect = this.getBounds();
JOptionPane.showMessageDialog(this, "" + rect);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
private void initComponents()
{
jPanel1 = new javax.swing.JPanel();
setLayout(null);
addComponentListener(new java.awt.event.ComponentAdapter()
{
@Override
public void componentResized(java.awt.event.ComponentEvent evt)
{
formComponentResized(evt);
}
@Override
public void componentShown(java.awt.event.ComponentEvent evt)
{
formComponentShown(evt);
}
});
add(jPanel1);
jPanel1.setBounds(80, 90, 280, 160);
}
// </editor-fold>//GEN-END:initComponents
private void formComponentShown(java.awt.event.ComponentEvent evt)//GEN-FIRST:event_formComponentShown
{//GEN-HEADEREND:event_formComponentShown
JOptionPane.showMessageDialog(this, "" + getWidth() + ", " + getHeight());
}//GEN-LAST:event_formComponentShown
private void formComponentResized(java.awt.event.ComponentEvent evt)//GEN-FIRST:event_formComponentResized
{//GEN-HEADEREND:event_formComponentResized
// TODO add your handling code here:
}//GEN-LAST:event_formComponentResized
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JPanel jPanel1;
// End of variables declaration//GEN-END:variables
}

View file

@ -0,0 +1,556 @@
/*
* 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 org.xbib.graphics.svg.app.beans;
import org.xbib.graphics.svg.SVGCache;
import org.xbib.graphics.svg.SVGDiagram;
import org.xbib.graphics.svg.SVGException;
import org.xbib.graphics.svg.SVGUniverse;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.net.URI;
import javax.swing.ImageIcon;
/**
*
* @author kitfox
*/
public class SVGIcon extends ImageIcon
{
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);
}
@Override
public Image getImage()
{
BufferedImage bi = new BufferedImage(getIconWidth(), getIconHeight(), BufferedImage.TYPE_INT_ARGB);
paintIcon(null, bi.getGraphics(), 0, 0);
return bi;
}
/**
* @return height of this icon
*/
public int getIconHeightIgnoreAutosize()
{
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 getIconWidthIgnoreAutosize()
{
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();
}
private boolean isAutoSizeBestFitUseFixedHeight(final int iconWidthIgnoreAutosize, final int iconHeightIgnoreAutosize,
final SVGDiagram diagram)
{
return iconHeightIgnoreAutosize/diagram.getHeight() < iconWidthIgnoreAutosize/diagram.getWidth();
}
@Override
public int getIconWidth()
{
final int iconWidthIgnoreAutosize = getIconWidthIgnoreAutosize();
final int iconHeightIgnoreAutosize = getIconHeightIgnoreAutosize();
final SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
if (preferredSize != null && (autosize == AUTOSIZE_VERT ||
(autosize == AUTOSIZE_BESTFIT && isAutoSizeBestFitUseFixedHeight(iconWidthIgnoreAutosize, iconHeightIgnoreAutosize, diagram))))
{
final double aspectRatio = diagram.getHeight()/diagram.getWidth();
return (int)(iconHeightIgnoreAutosize / aspectRatio);
}
else
{
return iconWidthIgnoreAutosize;
}
}
@Override
public int getIconHeight()
{
final int iconWidthIgnoreAutosize = getIconWidthIgnoreAutosize();
final int iconHeightIgnoreAutosize = getIconHeightIgnoreAutosize();
final SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
if (preferredSize != null && (autosize == AUTOSIZE_HORIZ ||
(autosize == AUTOSIZE_BESTFIT && !isAutoSizeBestFitUseFixedHeight(iconWidthIgnoreAutosize, iconHeightIgnoreAutosize, diagram))))
{
final double aspectRatio = diagram.getHeight()/diagram.getWidth();
return (int)(iconWidthIgnoreAutosize * aspectRatio);
}
else
{
return iconHeightIgnoreAutosize;
}
}
/**
* 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
*/
@Override
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 = getIconWidthIgnoreAutosize();
final int height = getIconHeightIgnoreAutosize();
// 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
*/
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);
}
}

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.2" maxVersion="1.2" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
</Form>

View file

@ -0,0 +1,342 @@
/*
* 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:43 AM
*/
package org.xbib.graphics.svg.app.beans;
import org.xbib.graphics.svg.SVGCache;
import org.xbib.graphics.svg.SVGDiagram;
import org.xbib.graphics.svg.SVGException;
import org.xbib.graphics.svg.SVGUniverse;
import java.awt.*;
import java.awt.geom.*;
import java.net.*;
import javax.swing.*;
/**
*
* @author kitfox
*/
public class SVGPanel extends JPanel
{
public static final long serialVersionUID = 1;
public static final String PROP_AUTOSIZE = "PROP_AUTOSIZE";
SVGUniverse svgUniverse = SVGCache.getSVGUniverse();
private boolean antiAlias;
// 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;
/** Creates new form SVGIcon */
public SVGPanel()
{
initComponents();
}
public int getSVGHeight()
{
if (autosize == AUTOSIZE_VERT || autosize == AUTOSIZE_STRETCH
|| autosize == AUTOSIZE_BESTFIT)
{
return getPreferredSize().height;
}
SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
if (diagram == null)
{
return 0;
}
return (int)diagram.getHeight();
}
public int getSVGWidth()
{
if (autosize == AUTOSIZE_HORIZ || autosize == AUTOSIZE_STRETCH
|| autosize == AUTOSIZE_BESTFIT)
{
return getPreferredSize().width;
}
SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
if (diagram == null)
{
return 0;
}
return (int)diagram.getWidth();
}
@Override
public void paintComponent(Graphics gg)
{
super.paintComponent(gg);
Graphics2D g = (Graphics2D)gg.create();
paintComponent(g);
g.dispose();
}
private void paintComponent(Graphics2D g)
{
Object oldAliasHint = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAlias ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
SVGDiagram diagram = svgUniverse.getDiagram(svgURI);
if (diagram == null)
{
return;
}
if (autosize == AUTOSIZE_NONE)
{
try
{
diagram.render(this, g);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAliasHint);
}
catch (SVGException e)
{
throw new RuntimeException(e);
}
return;
}
Dimension dim = getSize();
final int width = dim.width;
final int height = dim.height;
// final Rectangle2D.Double rect = new Rectangle2D.Double();
// diagram.getViewRect(rect);
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.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAliasHint);
}
public SVGUniverse getSvgUniverse()
{
return svgUniverse;
}
public void setSvgUniverse(SVGUniverse svgUniverse)
{
SVGUniverse old = this.svgUniverse;
this.svgUniverse = svgUniverse;
firePropertyChange("svgUniverse", old, svgUniverse);
}
public URI getSvgURI()
{
return svgURI;
}
public void setSvgURI(URI svgURI)
{
URI old = this.svgURI;
this.svgURI = svgURI;
firePropertyChange("svgURI", old, svgURI);
}
/**
* Most resources your component will want to access will be resources on your classpath.
* This method will interpret the passed string as a path in the classpath and use
* Class.getResource() to determine the URI of the SVG.
*/
public void setSvgResourcePath(String resourcePath) throws SVGException
{
URI old = this.svgURI;
try
{
svgURI = new URI(getClass().getResource(resourcePath).toString());
//System.err.println("SVGPanel: new URI " + svgURI + " from path " + resourcePath);
firePropertyChange("svgURI", old, svgURI);
repaint();
}
catch (Exception e)
{
throw new SVGException("Could not resolve path " + resourcePath, 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
*/
public void setScaleToFit(boolean scaleToFit)
{
setAutosize(AUTOSIZE_STRETCH);
// boolean old = this.scaleToFit;
// this.scaleToFit = scaleToFit;
// firePropertyChange("scaleToFit", old, scaleToFit);
}
/**
* @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;
firePropertyChange("antiAlias", old, antiAlias);
}
/**
* @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;
firePropertyChange(PROP_AUTOSIZE, oldAutosize, autosize);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
private void initComponents()
{
setLayout(new java.awt.BorderLayout());
}
// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
// End of variables declaration//GEN-END:variables
}

View file

@ -0,0 +1,129 @@
/*
* 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
*/
package org.xbib.graphics.svg.app.data;
import org.xbib.graphics.svg.SVGConst;
import org.xbib.graphics.svg.util.Base64InputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author kitfox
*/
public class Handler extends URLStreamHandler
{
class Connection extends URLConnection
{
String mime;
byte[] buf;
public Connection(URL url)
{
super(url);
String path = url.getPath();
int idx = path.indexOf(';');
mime = path.substring(0, idx);
String content = path.substring(idx + 1);
if (content.startsWith("base64,"))
{
content = content.substring(7);
try
{
//byte[] buf2 = new sun.misc.BASE64Decoder().decodeBuffer(content);
//buf = new sun.misc.BASE64Decoder().decodeBuffer(content);
ByteArrayInputStream bis = new ByteArrayInputStream(content.getBytes());
Base64InputStream b64is = new Base64InputStream(bis);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] tmp = new byte[2056];
for (int size = b64is.read(tmp); size != -1; size = b64is.read(tmp))
{
bout.write(tmp, 0, size);
}
buf = bout.toByteArray();
}
catch (IOException e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
}
}
}
@Override
public void connect() throws IOException
{
}
@Override
public String getHeaderField(String name)
{
if ("content-type".equals(name))
{
return mime;
}
return super.getHeaderField(name);
}
@Override
public InputStream getInputStream() throws IOException
{
return new ByteArrayInputStream(buf);
}
// public Object getContent() throws IOException
// {
// BufferedImage img = ImageIO.read(getInputStream());
// }
}
@Override
protected URLConnection openConnection(URL u) throws IOException
{
return new Connection(u);
}
}

View file

@ -0,0 +1,56 @@
/*
* 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
*/
package org.xbib.graphics.svg.app.data;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
/**
*
* @author kitfox
*/
public class HandlerFactory implements URLStreamHandlerFactory
{
static Handler handler = new Handler();
public URLStreamHandler createURLStreamHandler(String protocol)
{
if ("data".equals(protocol))
{
return handler;
}
return null;
}
}

View file

@ -0,0 +1,86 @@
/*
* 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 1, 2004, 6:40 AM
*/
package org.xbib.graphics.svg.composite;
import org.xbib.graphics.svg.SVGConst;
import java.awt.*;
import java.awt.image.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class AdobeComposite implements Composite
{
public static final int CT_NORMAL = 0;
public static final int CT_MULTIPLY = 1;
public static final int CT_LAST = 2;
final int compositeType;
final float extraAlpha;
/**
* Creates a new instance of AdobeComposite
* @param compositeType
* @param extraAlpha
*/
public AdobeComposite(int compositeType, float extraAlpha)
{
this.compositeType = compositeType;
this.extraAlpha = extraAlpha;
if (compositeType < 0 || compositeType >= CT_LAST)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, "Invalid composite type");
}
if (extraAlpha < 0f || extraAlpha > 1f)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, "Invalid alpha");
}
}
public int getCompositeType() { return compositeType; }
public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints)
{
return new AdobeCompositeContext(compositeType, extraAlpha);
}
}

View file

@ -0,0 +1,109 @@
/*
* 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 1, 2004, 6:41 AM
*/
package org.xbib.graphics.svg.composite;
import java.awt.*;
import java.awt.image.*;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class AdobeCompositeContext implements CompositeContext
{
final int compositeType;
final float extraAlpha;
float[] rgba_src = new float[4];
float[] rgba_dstIn = new float[4];
float[] rgba_dstOut = new float[4];
/** Creates a new instance of AdobeCompositeContext
* @param compositeType
* @param extraAlpha
*/
public AdobeCompositeContext(int compositeType, float extraAlpha)
{
this.compositeType = compositeType;
this.extraAlpha = extraAlpha;
rgba_dstOut[3] = 1f;
}
public void compose(Raster src, Raster dstIn, WritableRaster dstOut)
{
int width = src.getWidth();
int height = src.getHeight();
for (int j = 0; j < height; j++)
{
for (int i = 0; i < width; i++)
{
src.getPixel(i, j, rgba_src);
dstIn.getPixel(i, j, rgba_dstIn);
//Ignore transparent pixels
if (rgba_src[3] == 0)
{
// dstOut.setPixel(i, j, rgba_dstIn);
continue;
}
float alpha = rgba_src[3];
switch (compositeType)
{
default:
case AdobeComposite.CT_NORMAL:
rgba_dstOut[0] = rgba_src[0] * alpha + rgba_dstIn[0] * (1f - alpha);
rgba_dstOut[1] = rgba_src[1] * alpha + rgba_dstIn[1] * (1f - alpha);
rgba_dstOut[2] = rgba_src[2] * alpha + rgba_dstIn[2] * (1f - alpha);
break;
case AdobeComposite.CT_MULTIPLY:
rgba_dstOut[0] = rgba_src[0] * rgba_dstIn[0] * alpha + rgba_dstIn[0] * (1f - alpha);
rgba_dstOut[1] = rgba_src[1] * rgba_dstIn[1] * alpha + rgba_dstIn[1] * (1f - alpha);
rgba_dstOut[2] = rgba_src[2] * rgba_dstIn[2] * alpha + rgba_dstIn[2] * (1f - alpha);
break;
}
}
}
}
public void dispose() {
}
}

View file

@ -0,0 +1,283 @@
/*
* 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 January 26, 2004, 8:40 PM
*/
package org.xbib.graphics.svg.pathcmd;
//import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
import java.awt.*;
import java.awt.geom.*;
/**
* This is a little used SVG function, as most editors will save curves as
* Beziers. To reduce the need to rely on the Batik library, this functionallity
* is being bypassed for the time being. In the future, it would be nice to
* extend the GeneralPath command to include the arcTo ability provided by Batik.
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Arc extends PathCommand
{
public float rx = 0f;
public float ry = 0f;
public float xAxisRot = 0f;
public boolean largeArc = false;
public boolean sweep = false;
public float x = 0f;
public float y = 0f;
/** Creates a new instance of MoveTo */
public Arc() {
}
public Arc(boolean isRelative, float rx, float ry, float xAxisRot, boolean largeArc, boolean sweep, float x, float y) {
super(isRelative);
this.rx = rx;
this.ry = ry;
this.xAxisRot = xAxisRot;
this.largeArc = largeArc;
this.sweep = sweep;
this.x = x;
this.y = y;
}
// public void appendPath(ExtendedGeneralPath path, BuildHistory hist)
@Override
public void appendPath(GeneralPath path, BuildHistory hist)
{
float offx = isRelative ? hist.lastPoint.x : 0f;
float offy = isRelative ? hist.lastPoint.y : 0f;
arcTo(path, rx, ry, xAxisRot, largeArc, sweep,
x + offx, y + offy,
hist.lastPoint.x, hist.lastPoint.y);
// path.lineTo(x + offx, y + offy);
// hist.setPoint(x + offx, y + offy);
hist.setLastPoint(x + offx, y + offy);
hist.setLastKnot(x + offx, y + offy);
}
@Override
public int getNumKnotsAdded()
{
return 6;
}
/**
* Adds an elliptical arc, defined by two radii, an angle from the
* x-axis, a flag to choose the large arc or not, a flag to
* indicate if we increase or decrease the angles and the final
* point of the arc.
*
* @param path The path that the arc will be appended to.
*
* @param rx the x radius of the ellipse
* @param ry the y radius of the ellipse
*
* @param angle the angle from the x-axis of the current
* coordinate system to the x-axis of the ellipse in degrees.
*
* @param largeArcFlag the large arc flag. If true the arc
* spanning less than or equal to 180 degrees is chosen, otherwise
* the arc spanning greater than 180 degrees is chosen
*
* @param sweepFlag the sweep flag. If true the line joining
* center to arc sweeps through decreasing angles otherwise it
* sweeps through increasing angles
*
* @param x the absolute x coordinate of the final point of the arc.
* @param y the absolute y coordinate of the final point of the arc.
* @param x0 - The absolute x coordinate of the initial point of the arc.
* @param y0 - The absolute y coordinate of the initial point of the arc.
*/
public void arcTo(GeneralPath path, float rx, float ry,
float angle,
boolean largeArcFlag,
boolean sweepFlag,
float x, float y, float x0, float y0)
{
// Ensure radii are valid
if (rx == 0 || ry == 0) {
path.lineTo((float) x, (float) y);
return;
}
if (x0 == x && y0 == y) {
// If the endpoints (x, y) and (x0, y0) are identical, then this
// is equivalent to omitting the elliptical arc segment entirely.
return;
}
Arc2D arc = computeArc(x0, y0, rx, ry, angle,
largeArcFlag, sweepFlag, x, y);
if (arc == null) return;
AffineTransform t = AffineTransform.getRotateInstance
(Math.toRadians(angle), arc.getCenterX(), arc.getCenterY());
Shape s = t.createTransformedShape(arc);
path.append(s, true);
}
/**
* This constructs an unrotated Arc2D from the SVG specification of an
* Elliptical arc. To get the final arc you need to apply a rotation
* transform such as:
*
* AffineTransform.getRotateInstance
* (angle, arc.getX()+arc.getWidth()/2, arc.getY()+arc.getHeight()/2);
*
* @param x0 origin of arc in x
* @param y0 origin of arc in y
* @param rx radius of arc in x
* @param ry radius of arc in y
* @param angle number of radians in arc
* @param largeArcFlag
* @param sweepFlag
* @param x ending coordinate of arc in x
* @param y ending coordinate of arc in y
* @return arc shape
*
*/
public static Arc2D computeArc(double x0, double y0,
double rx, double ry,
double angle,
boolean largeArcFlag,
boolean sweepFlag,
double x, double y) {
//
// Elliptical arc implementation based on the SVG specification notes
//
// Compute the half distance between the current and the final point
double dx2 = (x0 - x) / 2.0;
double dy2 = (y0 - y) / 2.0;
// Convert angle from degrees to radians
angle = Math.toRadians(angle % 360.0);
double cosAngle = Math.cos(angle);
double sinAngle = Math.sin(angle);
//
// Step 1 : Compute (x1, y1)
//
double x1 = (cosAngle * dx2 + sinAngle * dy2);
double y1 = (-sinAngle * dx2 + cosAngle * dy2);
// Ensure radii are large enough
rx = Math.abs(rx);
ry = Math.abs(ry);
double Prx = rx * rx;
double Pry = ry * ry;
double Px1 = x1 * x1;
double Py1 = y1 * y1;
// check that radii are large enough
double radiiCheck = Px1/Prx + Py1/Pry;
if (radiiCheck > 1) {
rx = Math.sqrt(radiiCheck) * rx;
ry = Math.sqrt(radiiCheck) * ry;
Prx = rx * rx;
Pry = ry * ry;
}
//
// Step 2 : Compute (cx1, cy1)
//
double sign = (largeArcFlag == sweepFlag) ? -1 : 1;
double sq = ((Prx*Pry)-(Prx*Py1)-(Pry*Px1)) / ((Prx*Py1)+(Pry*Px1));
sq = (sq < 0) ? 0 : sq;
double coef = (sign * Math.sqrt(sq));
double cx1 = coef * ((rx * y1) / ry);
double cy1 = coef * -((ry * x1) / rx);
//
// Step 3 : Compute (cx, cy) from (cx1, cy1)
//
double sx2 = (x0 + x) / 2.0;
double sy2 = (y0 + y) / 2.0;
double cx = sx2 + (cosAngle * cx1 - sinAngle * cy1);
double cy = sy2 + (sinAngle * cx1 + cosAngle * cy1);
//
// Step 4 : Compute the angleStart (angle1) and the angleExtent (dangle)
//
double ux = (x1 - cx1) / rx;
double uy = (y1 - cy1) / ry;
double vx = (-x1 - cx1) / rx;
double vy = (-y1 - cy1) / ry;
double p, n;
// Compute the angle start
n = Math.sqrt((ux * ux) + (uy * uy));
p = ux; // (1 * ux) + (0 * uy)
sign = (uy < 0) ? -1d : 1d;
double angleStart = Math.toDegrees(sign * Math.acos(p / n));
// Compute the angle extent
n = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
p = ux * vx + uy * vy;
sign = (ux * vy - uy * vx < 0) ? -1d : 1d;
double angleExtent = Math.toDegrees(sign * Math.acos(p / n));
if(!sweepFlag && angleExtent > 0) {
angleExtent -= 360f;
} else if (sweepFlag && angleExtent < 0) {
angleExtent += 360f;
}
angleExtent %= 360f;
angleStart %= 360f;
//
// We can now build the resulting Arc2D in double precision
//
Arc2D.Double arc = new Arc2D.Double();
arc.x = cx - rx;
arc.y = cy - ry;
arc.width = rx * 2.0;
arc.height = ry * 2.0;
arc.start = -angleStart;
arc.extent = -angleExtent;
return arc;
}
@Override
public String toString()
{
return "A " + rx + " " + ry
+ " " + xAxisRot + " " + largeArc
+ " " + sweep
+ " " + x + " " + y;
}
}

View file

@ -0,0 +1,96 @@
/*
* 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 January 26, 2004, 9:18 PM
*/
package org.xbib.graphics.svg.pathcmd;
import java.awt.geom.Point2D;
/**
* When building a path from command segments, most need to cache information
* (such as the point finished at) for future commands. This structure allows
* that
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class BuildHistory
{
// Point2D.Float[] history = new Point2D.Float[2];
// Point2D.Float[] history = {new Point2D.Float(), new Point2D.Float()};
// Point2D.Float start = new Point2D.Float();
Point2D.Float startPoint = new Point2D.Float();
Point2D.Float lastPoint = new Point2D.Float();
Point2D.Float lastKnot = new Point2D.Float();
boolean init;
//int length = 0;
/**
* Creates a new instance of BuildHistory
*/
public BuildHistory()
{
}
public void setStartPoint(float x, float y)
{
startPoint.setLocation(x, y);
}
public void setLastPoint(float x, float y)
{
lastPoint.setLocation(x, y);
}
public void setLastKnot(float x, float y)
{
lastKnot.setLocation(x, y);
}
// public void setPoint(float x, float y)
// {
// history[0].setLocation(x, y);
// length = 1;
// }
// public void setStart(float x, float y)
// {
// start.setLocation(x, y);
// }
// public void setPointAndKnot(float x, float y, float kx, float ky)
// {
// history[0].setLocation(x, y);
// history[1].setLocation(kx, ky);
// length = 2;
// }
}

View file

@ -0,0 +1,97 @@
/*
* 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 January 26, 2004, 8:40 PM
*/
package org.xbib.graphics.svg.pathcmd;
//import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
import java.awt.geom.*;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Cubic extends PathCommand {
public float k1x = 0f;
public float k1y = 0f;
public float k2x = 0f;
public float k2y = 0f;
public float x = 0f;
public float y = 0f;
/** Creates a new instance of MoveTo */
public Cubic() {
}
@Override
public String toString()
{
return "C " + k1x + " " + k1y
+ " " + k2x + " " + k2y
+ " " + x + " " + y;
}
public Cubic(boolean isRelative, float k1x, float k1y, float k2x, float k2y, float x, float y) {
super(isRelative);
this.k1x = k1x;
this.k1y = k1y;
this.k2x = k2x;
this.k2y = k2y;
this.x = x;
this.y = y;
}
// public void appendPath(ExtendedGeneralPath path, BuildHistory hist)
@Override
public void appendPath(GeneralPath path, BuildHistory hist)
{
float offx = isRelative ? hist.lastPoint.x : 0f;
float offy = isRelative ? hist.lastPoint.y : 0f;
path.curveTo(k1x + offx, k1y + offy,
k2x + offx, k2y + offy,
x + offx, y + offy);
// hist.setPointAndKnot(x + offx, y + offy, k2x + offx, k2y + offy);
hist.setLastPoint(x + offx, y + offy);
hist.setLastKnot(k2x + offx, k2y + offy);
}
@Override
public int getNumKnotsAdded()
{
return 6;
}
}

View file

@ -0,0 +1,97 @@
/*
* 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 January 26, 2004, 8:40 PM
*/
package org.xbib.graphics.svg.pathcmd;
//import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
import java.awt.geom.*;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class CubicSmooth extends PathCommand {
public float x = 0f;
public float y = 0f;
public float k2x = 0f;
public float k2y = 0f;
/** Creates a new instance of MoveTo */
public CubicSmooth() {
}
public CubicSmooth(boolean isRelative, float k2x, float k2y, float x, float y) {
super(isRelative);
this.k2x = k2x;
this.k2y = k2y;
this.x = x;
this.y = y;
}
// public void appendPath(ExtendedGeneralPath path, BuildHistory hist)
@Override
public void appendPath(GeneralPath path, BuildHistory hist)
{
float offx = isRelative ? hist.lastPoint.x : 0f;
float offy = isRelative ? hist.lastPoint.y : 0f;
float oldKx = hist.lastKnot.x;
float oldKy = hist.lastKnot.y;
float oldX = hist.lastPoint.x;
float oldY = hist.lastPoint.y;
//Calc knot as reflection of old knot
float k1x = oldX * 2f - oldKx;
float k1y = oldY * 2f - oldKy;
path.curveTo(k1x, k1y, k2x + offx, k2y + offy, x + offx, y + offy);
hist.setLastPoint(x + offx, y + offy);
hist.setLastKnot(k2x + offx, k2y + offy);
}
@Override
public int getNumKnotsAdded()
{
return 6;
}
@Override
public String toString()
{
return "S " + k2x + " " + k2y
+ " " + x + " " + y;
}
}

View file

@ -0,0 +1,83 @@
/*
* 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 January 26, 2004, 8:40 PM
*/
package org.xbib.graphics.svg.pathcmd;
//import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
import java.awt.geom.*;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Horizontal extends PathCommand {
public float x = 0f;
/** Creates a new instance of MoveTo */
public Horizontal() {
}
@Override
public String toString()
{
return "H " + x;
}
public Horizontal(boolean isRelative, float x) {
super(isRelative);
this.x = x;
}
// public void appendPath(ExtendedGeneralPath path, BuildHistory hist)
@Override
public void appendPath(GeneralPath path, BuildHistory hist)
{
float offx = isRelative ? hist.lastPoint.x : 0f;
float offy = hist.lastPoint.y;
path.lineTo(x + offx, offy);
hist.setLastPoint(x + offx, offy);
hist.setLastKnot(x + offx, offy);
}
@Override
public int getNumKnotsAdded()
{
return 2;
}
}

View file

@ -0,0 +1,85 @@
/*
* 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 January 26, 2004, 8:40 PM
*/
package org.xbib.graphics.svg.pathcmd;
//import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
import java.awt.geom.*;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class LineTo extends PathCommand {
public float x = 0f;
public float y = 0f;
/** Creates a new instance of MoveTo */
public LineTo() {
}
public LineTo(boolean isRelative, float x, float y) {
super(isRelative);
this.x = x;
this.y = y;
}
// public void appendPath(ExtendedGeneralPath path, BuildHistory hist)
@Override
public void appendPath(GeneralPath path, BuildHistory hist)
{
float offx = isRelative ? hist.lastPoint.x : 0f;
float offy = isRelative ? hist.lastPoint.y : 0f;
path.lineTo(x + offx, y + offy);
hist.setLastPoint(x + offx, y + offy);
hist.setLastKnot(x + offx, y + offy);
}
@Override
public int getNumKnotsAdded()
{
return 2;
}
@Override
public String toString()
{
return "L " + x + " " + y;
}
}

View file

@ -0,0 +1,87 @@
/*
* 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 January 26, 2004, 8:40 PM
*/
package org.xbib.graphics.svg.pathcmd;
//import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
import java.awt.geom.*;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class MoveTo extends PathCommand {
public float x = 0f;
public float y = 0f;
/** Creates a new instance of MoveTo */
public MoveTo() {
}
public MoveTo(boolean isRelative, float x, float y) {
super(isRelative);
this.x = x;
this.y = y;
}
// public void appendPath(ExtendedGeneralPath path, BuildHistory hist)
@Override
public void appendPath(GeneralPath path, BuildHistory hist)
{
float offx = isRelative ? hist.lastPoint.x : 0f;
float offy = isRelative ? hist.lastPoint.y : 0f;
path.moveTo(x + offx, y + offy);
hist.setStartPoint(x + offx, y + offy);
hist.setLastPoint(x + offx, y + offy);
hist.setLastKnot(x + offx, y + offy);
}
@Override
public int getNumKnotsAdded()
{
return 2;
}
@Override
public String toString()
{
return "M " + x + " " + y;
}
}

View file

@ -0,0 +1,65 @@
/*
* 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 January 26, 2004, 8:39 PM
*/
package org.xbib.graphics.svg.pathcmd;
//import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
import java.awt.geom.*;
/**
* This is the element of a path and contains instructions for rendering a
* portion of the path
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
abstract public class PathCommand {
public boolean isRelative = false;
/** Creates a new instance of PathCommand */
public PathCommand() {
}
public PathCommand(boolean isRelative) {
this.isRelative = isRelative;
}
// abstract public void appendPath(ExtendedGeneralPath path, BuildHistory hist);
abstract public void appendPath(GeneralPath path, BuildHistory hist);
abstract public int getNumKnotsAdded();
}

View file

@ -0,0 +1,251 @@
/*
* 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
*
*/
package org.xbib.graphics.svg.pathcmd;
import java.util.ArrayList;
import java.util.List;
/**
* A helper for parsing {@link PathCommand}s.
*
* @author Jannis Weis
*/
public class PathParser
{
private final String input;
private final int inputLength;
private int index;
private char currentCommand;
public PathParser(String input) {
this.input = input.trim();
this.inputLength = this.input.length();
}
private boolean isCommandChar(char c)
{
return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';
}
private boolean isWhiteSpaceOrSeparator(char c)
{
return c <= ' ' || c == ',';
}
private char peek()
{
return input.charAt(index);
}
private void consume()
{
index++;
}
private boolean hasNext()
{
return index < inputLength;
}
// This only checks for the rough structure of a number as we need to know
// when to separate the next token.
// Explicit parsing is done by Float#parseFloat.
private boolean isValidNumberChar(char c, NumberCharState state)
{
boolean valid = '0' <= c && c <= '9';
if (valid && state.iteration == 1 && input.charAt(index - 1) == '0')
{
// Break up combined zeros into multiple numbers.
return false;
}
state.signAllowed = state.signAllowed && !valid;
if (state.dotAllowed && !valid)
{
valid = c == '.';
state.dotAllowed = !valid;
}
if (state.signAllowed && !valid)
{
valid = c == '+' || c == '-';
state.signAllowed = valid;
}
if (state.exponentAllowed && !valid)
{
// Possible exponent notation. Needs at least one preceding number
valid = c == 'e' || c == 'E';
state.exponentAllowed = !valid;
state.signAllowed = valid;
}
state.iteration++;
return valid;
}
private void consumeWhiteSpaceOrSeparator() {
while (hasNext() && isWhiteSpaceOrSeparator(peek())) {
consume();
}
}
private float nextFloat()
{
int start = index;
NumberCharState state = new NumberCharState();
while (hasNext() && isValidNumberChar(peek(), state)) {
consume();
}
int end = index;
consumeWhiteSpaceOrSeparator();
String token = input.substring(start, end);
try
{
return Float.parseFloat(token);
} catch (NumberFormatException e)
{
String msg = "Unexpected element while parsing cmd '" + currentCommand
+ "' encountered token '" + token + "' rest=" + input.substring(start, Math.min(input.length(), start + 10))
+ " (index=" + index + " in input=" + input + ")";
throw new IllegalStateException(msg, e);
}
}
public PathCommand[] parsePathCommand()
{
List<PathCommand> commands = new ArrayList<>();
currentCommand = 'Z';
while (hasNext())
{
char peekChar = peek();
if (isCommandChar(peekChar))
{
consume();
currentCommand = peekChar;
}
consumeWhiteSpaceOrSeparator();
PathCommand cmd;
switch (currentCommand)
{
case 'M':
cmd = new MoveTo(false, nextFloat(), nextFloat());
currentCommand = 'L';
break;
case 'm':
cmd = new MoveTo(true, nextFloat(), nextFloat());
currentCommand = 'l';
break;
case 'L':
cmd = new LineTo(false, nextFloat(), nextFloat());
break;
case 'l':
cmd = new LineTo(true, nextFloat(), nextFloat());
break;
case 'H':
cmd = new Horizontal(false, nextFloat());
break;
case 'h':
cmd = new Horizontal(true, nextFloat());
break;
case 'V':
cmd = new Vertical(false, nextFloat());
break;
case 'v':
cmd = new Vertical(true, nextFloat());
break;
case 'A':
cmd = new Arc(false, nextFloat(), nextFloat(),
nextFloat(),
nextFloat() == 1f, nextFloat() == 1f,
nextFloat(), nextFloat());
break;
case 'a':
cmd = new Arc(true, nextFloat(), nextFloat(),
nextFloat(),
nextFloat() == 1f, nextFloat() == 1f,
nextFloat(), nextFloat());
break;
case 'Q':
cmd = new Quadratic(false, nextFloat(), nextFloat(),
nextFloat(), nextFloat());
break;
case 'q':
cmd = new Quadratic(true, nextFloat(), nextFloat(),
nextFloat(), nextFloat());
break;
case 'T':
cmd = new QuadraticSmooth(false, nextFloat(), nextFloat());
break;
case 't':
cmd = new QuadraticSmooth(true, nextFloat(), nextFloat());
break;
case 'C':
cmd = new Cubic(false, nextFloat(), nextFloat(),
nextFloat(), nextFloat(),
nextFloat(), nextFloat());
break;
case 'c':
cmd = new Cubic(true, nextFloat(), nextFloat(),
nextFloat(), nextFloat(),
nextFloat(), nextFloat());
break;
case 'S':
cmd = new CubicSmooth(false, nextFloat(), nextFloat(),
nextFloat(), nextFloat());
break;
case 's':
cmd = new CubicSmooth(true, nextFloat(), nextFloat(),
nextFloat(), nextFloat());
break;
case 'Z':
case 'z':
cmd = new Terminal();
break;
default:
throw new RuntimeException("Invalid path element "
+ currentCommand + "(at index=" + index + " in input=" + input + ")");
}
commands.add(cmd);
}
return commands.toArray(new PathCommand[0]);
}
private static class NumberCharState
{
int iteration = 0;
boolean dotAllowed = true;
boolean signAllowed = true;
boolean exponentAllowed = true;
}
}

View file

@ -0,0 +1,101 @@
/*
* 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 May 10, 2005, 5:56 AM
*/
package org.xbib.graphics.svg.pathcmd;
import java.awt.geom.*;
/**
*
* @author kitfox
*/
public class PathUtil
{
/** Creates a new instance of PathUtil */
public PathUtil()
{
}
/**
* Converts a GeneralPath into an SVG representation
*
* @param path The shape to be encoded
* @return A string encoding the path using the SVG path notation
*/
public static String buildPathString(GeneralPath path)
{
float[] coords = new float[6];
StringBuffer sb = new StringBuffer();
for (PathIterator pathIt = path.getPathIterator(new AffineTransform()); !pathIt.isDone(); pathIt.next())
{
int segId = pathIt.currentSegment(coords);
switch (segId)
{
case PathIterator.SEG_CLOSE:
{
sb.append(" Z");
break;
}
case PathIterator.SEG_CUBICTO:
{
sb.append(" C " + coords[0] + " " + coords[1] + " " + coords[2] + " " + coords[3] + " " + coords[4] + " " + coords[5]);
break;
}
case PathIterator.SEG_LINETO:
{
sb.append(" L " + coords[0] + " " + coords[1]);
break;
}
case PathIterator.SEG_MOVETO:
{
sb.append(" M " + coords[0] + " " + coords[1]);
break;
}
case PathIterator.SEG_QUADTO:
{
sb.append(" Q " + coords[0] + " " + coords[1] + " " + coords[2] + " " + coords[3]);
break;
}
}
}
return sb.toString();
}
}

View file

@ -0,0 +1,89 @@
/*
* 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 January 26, 2004, 8:40 PM
*/
package org.xbib.graphics.svg.pathcmd;
//import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
import java.awt.geom.*;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Quadratic extends PathCommand {
public float kx = 0f;
public float ky = 0f;
public float x = 0f;
public float y = 0f;
/** Creates a new instance of MoveTo */
public Quadratic() {
}
@Override
public String toString()
{
return "Q " + kx + " " + ky
+ " " + x + " " + y;
}
public Quadratic(boolean isRelative, float kx, float ky, float x, float y) {
super(isRelative);
this.kx = kx;
this.ky = ky;
this.x = x;
this.y = y;
}
// public void appendPath(ExtendedGeneralPath path, BuildHistory hist)
@Override
public void appendPath(GeneralPath path, BuildHistory hist)
{
float offx = isRelative ? hist.lastPoint.x : 0f;
float offy = isRelative ? hist.lastPoint.y : 0f;
path.quadTo(kx + offx, ky + offy, x + offx, y + offy);
hist.setLastPoint(x + offx, y + offy);
hist.setLastKnot(kx + offx, ky + offy);
}
@Override
public int getNumKnotsAdded()
{
return 4;
}
}

View file

@ -0,0 +1,92 @@
/*
* 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 January 26, 2004, 8:40 PM
*/
package org.xbib.graphics.svg.pathcmd;
//import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
import java.awt.geom.*;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class QuadraticSmooth extends PathCommand {
public float x = 0f;
public float y = 0f;
/** Creates a new instance of MoveTo */
public QuadraticSmooth() {
}
@Override
public String toString()
{
return "T " + x + " " + y;
}
public QuadraticSmooth(boolean isRelative, float x, float y) {
super(isRelative);
this.x = x;
this.y = y;
}
// public void appendPath(ExtendedGeneralPath path, BuildHistory hist)
@Override
public void appendPath(GeneralPath path, BuildHistory hist)
{
float offx = isRelative ? hist.lastPoint.x : 0f;
float offy = isRelative ? hist.lastPoint.y : 0f;
float oldKx = hist.lastKnot.x;
float oldKy = hist.lastKnot.y;
float oldX = hist.lastPoint.x;
float oldY = hist.lastPoint.y;
//Calc knot as reflection of old knot
float kx = oldX * 2f - oldKx;
float ky = oldY * 2f - oldKy;
path.quadTo(kx, ky, x + offx, y + offy);
hist.setLastPoint(x + offx, y + offy);
hist.setLastKnot(kx, ky);
}
@Override
public int getNumKnotsAdded()
{
return 4;
}
}

View file

@ -0,0 +1,75 @@
/*
* 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 January 26, 2004, 8:40 PM
*/
package org.xbib.graphics.svg.pathcmd;
//import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
import java.awt.geom.*;
/**
* Finishes a path
*
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Terminal extends PathCommand {
/** Creates a new instance of MoveTo */
public Terminal() {
}
@Override
public String toString()
{
return "Z";
}
// public void appendPath(ExtendedGeneralPath path, BuildHistory hist)
@Override
public void appendPath(GeneralPath path, BuildHistory hist)
{
path.closePath();
hist.setLastPoint(hist.startPoint.x, hist.startPoint.y);
hist.setLastKnot(hist.startPoint.x, hist.startPoint.y);
}
@Override
public int getNumKnotsAdded()
{
return 0;
}
}

View file

@ -0,0 +1,82 @@
/*
* 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 January 26, 2004, 8:40 PM
*/
package org.xbib.graphics.svg.pathcmd;
//import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
import java.awt.geom.*;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class Vertical extends PathCommand {
public float y = 0f;
/** Creates a new instance of MoveTo */
public Vertical() {
}
@Override
public String toString()
{
return "V " + y;
}
public Vertical(boolean isRelative, float y) {
super(isRelative);
this.y = y;
}
// public void appendPath(ExtendedGeneralPath path, BuildHistory hist)
@Override
public void appendPath(GeneralPath path, BuildHistory hist)
{
float offx = hist.lastPoint.x;
float offy = isRelative ? hist.lastPoint.y : 0f;
path.lineTo(offx, y + offy);
hist.setLastPoint(offx, y + offy);
hist.setLastKnot(offx, y + offy);
}
@Override
public int getNumKnotsAdded()
{
return 2;
}
}

View file

@ -0,0 +1,69 @@
/*
* 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 1, 2004, 3:37 AM
*/
package org.xbib.graphics.svg.pattern;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class PatternPaint implements Paint
{
BufferedImage source; //Image we're rendering from
AffineTransform xform;
/** Creates a new instance of PatternPaint */
public PatternPaint(BufferedImage source, AffineTransform xform)
{
this.source = source;
this.xform = xform;
}
public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, RenderingHints hints)
{
return new PatternPaintContext(source, deviceBounds, xform, this.xform);
}
public int getTransparency()
{
return source.getColorModel().getTransparency();
}
}

View file

@ -0,0 +1,135 @@
/*
* 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 1, 2004, 3:37 AM
*/
package org.xbib.graphics.svg.pattern;
import org.xbib.graphics.svg.SVGConst;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class PatternPaintContext implements PaintContext
{
BufferedImage source; //Image we're rendering from
Rectangle deviceBounds; //int size of rectangle we're rendering to
// AffineTransform userXform; //xform from user space to device space
// AffineTransform distortXform; //distortion applied to this pattern
AffineTransform xform; //distortion applied to this pattern
int sourceWidth;
int sourceHeight;
//Raster we use to build tile
BufferedImage buf;
/** Creates a new instance of PatternPaintContext */
public PatternPaintContext(BufferedImage source, Rectangle deviceBounds, AffineTransform userXform, AffineTransform distortXform)
{
//System.err.println("Bounds " + deviceBounds);
this.source = source;
this.deviceBounds = deviceBounds;
try {
// this.distortXform = distortXform.createInverse();
// this.userXform = userXform.createInverse();
// xform = userXform.createInverse();
// xform.concatenate(distortXform.createInverse());
xform = distortXform.createInverse();
xform.concatenate(userXform.createInverse());
}
catch (Exception e)
{
Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e);
}
sourceWidth = source.getWidth();
sourceHeight = source.getHeight();
}
public void dispose() {
}
public ColorModel getColorModel() {
return source.getColorModel();
}
public Raster getRaster(int x, int y, int w, int h)
{
//System.err.println("" + x + ", " + y + ", " + w + ", " + h);
if (buf == null || buf.getWidth() != w || buf.getHeight() != h)
{
buf = new BufferedImage(w, h, source.getType());
}
// Point2D.Float srcPt = new Point2D.Float(), srcPt2 = new Point2D.Float(), destPt = new Point2D.Float();
Point2D.Float srcPt = new Point2D.Float(), destPt = new Point2D.Float();
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
destPt.setLocation(i + x, j + y);
xform.transform(destPt, srcPt);
// userXform.transform(destPt, srcPt2);
// distortXform.transform(srcPt2, srcPt);
int ii = ((int)srcPt.x) % sourceWidth;
if (ii < 0) ii += sourceWidth;
int jj = ((int)srcPt.y) % sourceHeight;
if (jj < 0) jj += sourceHeight;
buf.setRGB(i, j, source.getRGB(ii, jj));
}
}
return buf.getData();
}
public static void main(String[] argv)
{
int i = -4;
System.err.println("Hello " + (i % 4));
}
}

View file

@ -0,0 +1,48 @@
/*
* 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 July 23, 2007
*/
package org.xbib.graphics.svg.util;
/**
*
* @author kitfox
*/
public interface Base64Consts
{
final String BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
}

View file

@ -0,0 +1,146 @@
/*
* 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 July 23, 2007
*/
package org.xbib.graphics.svg.util;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
/**
*
* @author kitfox
*/
public class Base64InputStream extends FilterInputStream implements Base64Consts
{
static final HashMap<Byte, Integer> lookup64 = new HashMap<Byte, Integer>();
static {
byte[] ch = BASE64_CHARS.getBytes();
for (int i = 0; i < ch.length; i++)
{
lookup64.put(new Byte(ch[i]), new Integer(i));
}
}
int buf;
int charsInBuf;
/** Creates a new instance of Base64InputStream */
public Base64InputStream(InputStream in)
{
super(in);
}
@Override
public int read(byte[] b, int off, int len) throws IOException
{
for (int i = 0; i < len; ++i)
{
int val = read();
if (val == -1)
{
return i == 0 ? -1 : i;
}
b[off + i] = (byte)val;
}
return len;
}
@Override
public int read() throws IOException
{
if (charsInBuf == 0)
{
fillBuffer();
if (charsInBuf == 0)
{
return -1;
}
}
return (buf >> (--charsInBuf * 8)) & 0xff;
}
private void fillBuffer() throws IOException
{
//Read next 4 characters
int bitsRead = 0;
while (bitsRead < 24)
{
int val = in.read();
if (val == -1 || val == '=') break;
Integer lval = (Integer)lookup64.get(new Byte((byte)val));
if (lval == null) continue;
buf = buf << 6 | lval.byteValue();
bitsRead += 6;
}
switch (bitsRead)
{
case 6:
{
throw new RuntimeException("Invalid termination of base64 encoding.");
}
case 12:
{
buf >>= 4;
bitsRead = 8;
break;
}
case 18:
{
buf >>= 2;
bitsRead = 16;
break;
}
case 0:
case 24:
{
break;
}
default:
{
assert false : "Should never encounter other bit counts";
}
}
charsInBuf = bitsRead / 8;
}
}

View file

@ -0,0 +1,124 @@
/*
* 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 July 23, 2007
*/
package org.xbib.graphics.svg.util;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
*
* @author kitfox
*/
public class Base64OutputStream extends FilterOutputStream implements Base64Consts
{
int buf;
int bitsUsed;
int charsPrinted;
/** Creates a new instance of Base64OutputSream */
public Base64OutputStream(OutputStream out)
{
super(out);
}
@Override
public void close() throws IOException
{
writeBits();
super.close();
}
@Override
public void write(int b) throws IOException
{
buf = buf << 8 | (b & 0xff);
bitsUsed += 8;
if (bitsUsed == 24)
{
writeBits();
}
}
private void writeBits() throws IOException
{
int padSize;
//Pad unused bits with 0
switch (bitsUsed)
{
case 8:
{
bitsUsed = 12;
buf <<= 4;
padSize = 2;
break;
}
case 16:
{
bitsUsed = 18;
buf <<= 2;
padSize = 1;
break;
}
default:
{
padSize = 0;
break;
}
}
if (charsPrinted == 76)
{
out.write('\r');
out.write('\n');
charsPrinted = 0;
}
for (; bitsUsed > 0; bitsUsed -= 6)
{
int b = buf >> (bitsUsed - 6) & 0x3f;
out.write(BASE64_CHARS.charAt(b));
}
for (int i = 0; i < padSize; i++)
{
out.write('=');
}
charsPrinted += 4;
}
}

View file

@ -0,0 +1,171 @@
/*
* 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 24, 2015
*/
package org.xbib.graphics.svg.util;
import org.xbib.graphics.svg.Font;
import org.xbib.graphics.svg.FontFace;
import org.xbib.graphics.svg.Glyph;
import org.xbib.graphics.svg.MissingGlyph;
import org.xbib.graphics.svg.Text;
import java.awt.GraphicsEnvironment;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphMetrics;
import java.awt.font.GlyphVector;
import java.awt.font.LineMetrics;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
/**
*
* @author kitfox
*/
public class FontSystem extends Font
{
java.awt.Font sysFont;
HashMap<String, Glyph> glyphCache = new HashMap<>();
static HashSet<String> sysFontNames = new HashSet<>();
public static boolean checkIfSystemFontExists(String fontName)
{
if (sysFontNames.isEmpty())
{
for (String name: GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(Locale.ENGLISH))
{
sysFontNames.add(name);
}
}
return sysFontNames.contains(fontName);
}
public static FontSystem createFont(String[] fontFamilies, int fontStyle, int fontWeight, float fontSize)
{
for (String fontName: fontFamilies)
{
String javaFontName = mapJavaFontName(fontName);
if (checkIfSystemFontExists(javaFontName))
{
return new FontSystem(javaFontName, fontStyle, fontWeight, fontSize);
}
}
return null;
}
private static String mapJavaFontName(String fontName)
{
if ("serif".equals(fontName))
{
return java.awt.Font.SERIF;
}
else if ("sans-serif".equals(fontName))
{
return java.awt.Font.SANS_SERIF;
}
else if ("monospace".equals(fontName))
{
return java.awt.Font.MONOSPACED;
}
return fontName;
}
private FontSystem(String fontFamily, int fontStyle, int fontWeight, float fontSize)
{
int style;
switch (fontStyle)
{
case Text.TXST_ITALIC:
style = java.awt.Font.ITALIC;
break;
default:
style = java.awt.Font.PLAIN;
break;
}
int weight;
switch (fontWeight)
{
case Text.TXWE_BOLD:
case Text.TXWE_BOLDER:
weight = java.awt.Font.BOLD;
break;
default:
weight = java.awt.Font.PLAIN;
break;
}
sysFont = new java.awt.Font(fontFamily, style | weight, 1).deriveFont(fontSize);
FontRenderContext fontRenderContext = new FontRenderContext(null, true, true);
LineMetrics lineMetrics = sysFont.getLineMetrics("M", fontRenderContext);
FontFace face = new FontFace();
face.setAscent((int) lineMetrics.getAscent());
face.setDescent((int) lineMetrics.getDescent());
face.setUnitsPerEm((int) sysFont.getStringBounds("M", fontRenderContext).getWidth());
setFontFace(face);
}
@Override
public MissingGlyph getGlyph(String unicode)
{
FontRenderContext frc = new FontRenderContext(null, true, true);
GlyphVector vec = sysFont.createGlyphVector(frc, unicode);
Glyph glyph = (Glyph)glyphCache.get(unicode);
if (glyph == null)
{
glyph = new Glyph();
glyph.setPath(vec.getGlyphOutline(0));
GlyphMetrics gm = vec.getGlyphMetrics(0);
glyph.setHorizAdvX(gm.getAdvanceX());
glyph.setVertAdvY(gm.getAdvanceY());
glyph.setVertOriginX(0);
glyph.setVertOriginY(0);
glyphCache.put(unicode, glyph);
}
return glyph;
}
}

View file

@ -0,0 +1,181 @@
/*
* 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
*/
package org.xbib.graphics.svg.util;
import org.xbib.graphics.svg.Font;
import org.xbib.graphics.svg.SVGDiagram;
import org.xbib.graphics.svg.SVGElement;
import org.xbib.graphics.svg.SVGException;
import org.xbib.graphics.svg.Text;
import org.xbib.graphics.svg.xml.StyleAttribute;
import java.util.Arrays;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Utility class for parsing font information of an {@link SVGElement}.
*
* @author Jannis Weis
*/
public final class FontUtil
{
private static final String DEFAULT_FONT_FAMILY = "sans-serif";
private static final float DEFAULT_FONT_SIZE = 12f;
private static final int DEFAULT_LETTER_SPACING = 0;
private static final int DEFAULT_FONT_STYLE = Text.TXST_NORMAL;
private static final int DEFAULT_FONT_WEIGHT = Text.TXWE_NORMAL;
private FontUtil() {}
public final static class FontInfo {
public final String[] families;
public final float size;
public final int style;
public final int weight;
public final float letterSpacing;
public FontInfo(String[] families, float size, int style, int weight, float letterSpacing)
{
this.families = families;
this.size = size;
this.style = style;
this.weight = weight;
this.letterSpacing = letterSpacing;
}
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (!(o instanceof FontInfo)) return false;
FontInfo fontInfo = (FontInfo) o;
return Float.compare(fontInfo.size, size) == 0
&& style == fontInfo.style && weight == fontInfo.weight
&& Float.compare(fontInfo.letterSpacing, letterSpacing) == 0
&& Arrays.equals(families, fontInfo.families);
}
@Override
public int hashCode()
{
int result = Objects.hash(size, style, weight, letterSpacing);
result = 31 * result + Arrays.hashCode(families);
return result;
}
}
public static FontInfo parseFontInfo(SVGElement element, StyleAttribute sty) throws SVGException
{
String fontFamily = DEFAULT_FONT_FAMILY;
if (element.getStyle(sty.setName("font-family")))
{
fontFamily = sty.getStringValue();
}
float fontSize = DEFAULT_FONT_SIZE;
if (element.getStyle(sty.setName("font-size")))
{
fontSize = sty.getFloatValueWithUnits();
}
float letterSpacing = DEFAULT_LETTER_SPACING;
if (element.getStyle(sty.setName("letter-spacing")))
{
letterSpacing = sty.getFloatValueWithUnits();
}
int fontStyle = DEFAULT_FONT_STYLE;
if (element.getStyle(sty.setName("font-style")))
{
String s = sty.getStringValue();
if ("normal".equals(s))
{
fontStyle = Text.TXST_NORMAL;
} else if ("italic".equals(s))
{
fontStyle = Text.TXST_ITALIC;
} else if ("oblique".equals(s))
{
fontStyle = Text.TXST_OBLIQUE;
}
}
int fontWeight = DEFAULT_FONT_WEIGHT;
if (element.getStyle(sty.setName("font-weight")))
{
String s = sty.getStringValue();
if ("normal".equals(s))
{
fontWeight = Text.TXWE_NORMAL;
} else if ("bold".equals(s))
{
fontWeight = Text.TXWE_BOLD;
}
}
return new FontInfo(fontFamily.split(","), fontSize, fontStyle, fontWeight, letterSpacing);
}
public static Font getFont(FontInfo info, SVGDiagram diagram)
{
return getFont(info.families, info.style, info.weight, info.size, diagram);
}
private static Font getFont(String[] families, int fontStyle, int fontWeight, float fontSize, SVGDiagram diagram)
{
Font font = null;
for (String family : families)
{
font = diagram.getUniverse().getFont(family);
if (font != null) break;
}
if (font == null)
{
//Check system fonts
font = FontSystem.createFont(families, fontStyle, fontWeight, fontSize);
}
if (font == null)
{
Logger.getLogger(FontSystem.class.getName())
.log(Level.WARNING, "Could not create font " + Arrays.toString(families));
String[] defaultFont = new String[]{ FontUtil.DEFAULT_FONT_FAMILY };
font = FontSystem.createFont(defaultFont, fontStyle, fontWeight, fontSize);
}
return font;
}
}

View file

@ -0,0 +1,45 @@
/*
* 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 24, 2015
*/
package org.xbib.graphics.svg.util;
/**
*
* @author kitfox
*/
public class TextBuilder
{
}

View file

@ -0,0 +1,294 @@
/*
* 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 January 26, 2004, 4:34 AM
*/
package org.xbib.graphics.svg.xml;
import java.awt.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Mark McKay
* @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
*/
public class ColorTable
{
static final Map<String, Color> colorTable;
static {
HashMap<String, Color> table = new HashMap<String, Color>();
//We really should be interpreting the currentColor keyword as
// a reference to the referring node's color, but this quick hack
// will stop the program from crashing.
table.put("currentcolor", new Color(0x0));
table.put("aliceblue", new Color(0xf0f8ff));
table.put("antiquewhite", new Color(0xfaebd7));
table.put("aqua", new Color(0x00ffff));
table.put("aquamarine", new Color(0x7fffd4));
table.put("azure", new Color(0xf0ffff));
table.put("beige", new Color(0xf5f5dc));
table.put("bisque", new Color(0xffe4c4));
table.put("black", new Color(0x000000));
table.put("blanchedalmond", new Color(0xffebcd));
table.put("blue", new Color(0x0000ff));
table.put("blueviolet", new Color(0x8a2be2));
table.put("brown", new Color(0xa52a2a));
table.put("burlywood", new Color(0xdeb887));
table.put("cadetblue", new Color(0x5f9ea0));
table.put("chartreuse", new Color(0x7fff00));
table.put("chocolate", new Color(0xd2691e));
table.put("coral", new Color(0xff7f50));
table.put("cornflowerblue", new Color(0x6495ed));
table.put("cornsilk", new Color(0xfff8dc));
table.put("crimson", new Color(0xdc143c));
table.put("cyan", new Color(0x00ffff));
table.put("darkblue", new Color(0x00008b));
table.put("darkcyan", new Color(0x008b8b));
table.put("darkgoldenrod", new Color(0xb8860b));
table.put("darkgray", new Color(0xa9a9a9));
table.put("darkgreen", new Color(0x006400));
table.put("darkkhaki", new Color(0xbdb76b));
table.put("darkmagenta", new Color(0x8b008b));
table.put("darkolivegreen", new Color(0x556b2f));
table.put("darkorange", new Color(0xff8c00));
table.put("darkorchid", new Color(0x9932cc));
table.put("darkred", new Color(0x8b0000));
table.put("darksalmon", new Color(0xe9967a));
table.put("darkseagreen", new Color(0x8fbc8f));
table.put("darkslateblue", new Color(0x483d8b));
table.put("darkslategray", new Color(0x2f4f4f));
table.put("darkturquoise", new Color(0x00ced1));
table.put("darkviolet", new Color(0x9400d3));
table.put("deeppink", new Color(0xff1493));
table.put("deepskyblue", new Color(0x00bfff));
table.put("dimgray", new Color(0x696969));
table.put("dodgerblue", new Color(0x1e90ff));
table.put("feldspar", new Color(0xd19275));
table.put("firebrick", new Color(0xb22222));
table.put("floralwhite", new Color(0xfffaf0));
table.put("forestgreen", new Color(0x228b22));
table.put("fuchsia", new Color(0xff00ff));
table.put("gainsboro", new Color(0xdcdcdc));
table.put("ghostwhite", new Color(0xf8f8ff));
table.put("gold", new Color(0xffd700));
table.put("goldenrod", new Color(0xdaa520));
table.put("gray", new Color(0x808080));
table.put("green", new Color(0x008000));
table.put("greenyellow", new Color(0xadff2f));
table.put("honeydew", new Color(0xf0fff0));
table.put("hotpink", new Color(0xff69b4));
table.put("indianred", new Color(0xcd5c5c));
table.put("indigo", new Color(0x4b0082));
table.put("ivory", new Color(0xfffff0));
table.put("khaki", new Color(0xf0e68c));
table.put("lavender", new Color(0xe6e6fa));
table.put("lavenderblush", new Color(0xfff0f5));
table.put("lawngreen", new Color(0x7cfc00));
table.put("lemonchiffon", new Color(0xfffacd));
table.put("lightblue", new Color(0xadd8e6));
table.put("lightcoral", new Color(0xf08080));
table.put("lightcyan", new Color(0xe0ffff));
table.put("lightgoldenrodyellow", new Color(0xfafad2));
table.put("lightgrey", new Color(0xd3d3d3));
table.put("lightgreen", new Color(0x90ee90));
table.put("lightpink", new Color(0xffb6c1));
table.put("lightsalmon", new Color(0xffa07a));
table.put("lightseagreen", new Color(0x20b2aa));
table.put("lightskyblue", new Color(0x87cefa));
table.put("lightslateblue", new Color(0x8470ff));
table.put("lightslategray", new Color(0x778899));
table.put("lightsteelblue", new Color(0xb0c4de));
table.put("lightyellow", new Color(0xffffe0));
table.put("lime", new Color(0x00ff00));
table.put("limegreen", new Color(0x32cd32));
table.put("linen", new Color(0xfaf0e6));
table.put("magenta", new Color(0xff00ff));
table.put("maroon", new Color(0x800000));
table.put("mediumaquamarine", new Color(0x66cdaa));
table.put("mediumblue", new Color(0x0000cd));
table.put("mediumorchid", new Color(0xba55d3));
table.put("mediumpurple", new Color(0x9370d8));
table.put("mediumseagreen", new Color(0x3cb371));
table.put("mediumslateblue", new Color(0x7b68ee));
table.put("mediumspringgreen", new Color(0x00fa9a));
table.put("mediumturquoise", new Color(0x48d1cc));
table.put("mediumvioletred", new Color(0xc71585));
table.put("midnightblue", new Color(0x191970));
table.put("mintcream", new Color(0xf5fffa));
table.put("mistyrose", new Color(0xffe4e1));
table.put("moccasin", new Color(0xffe4b5));
table.put("navajowhite", new Color(0xffdead));
table.put("navy", new Color(0x000080));
table.put("oldlace", new Color(0xfdf5e6));
table.put("olive", new Color(0x808000));
table.put("olivedrab", new Color(0x6b8e23));
table.put("orange", new Color(0xffa500));
table.put("orangered", new Color(0xff4500));
table.put("orchid", new Color(0xda70d6));
table.put("palegoldenrod", new Color(0xeee8aa));
table.put("palegreen", new Color(0x98fb98));
table.put("paleturquoise", new Color(0xafeeee));
table.put("palevioletred", new Color(0xd87093));
table.put("papayawhip", new Color(0xffefd5));
table.put("peachpuff", new Color(0xffdab9));
table.put("peru", new Color(0xcd853f));
table.put("pink", new Color(0xffc0cb));
table.put("plum", new Color(0xdda0dd));
table.put("powderblue", new Color(0xb0e0e6));
table.put("purple", new Color(0x800080));
table.put("red", new Color(0xff0000));
table.put("rosybrown", new Color(0xbc8f8f));
table.put("royalblue", new Color(0x4169e1));
table.put("saddlebrown", new Color(0x8b4513));
table.put("salmon", new Color(0xfa8072));
table.put("sandybrown", new Color(0xf4a460));
table.put("seagreen", new Color(0x2e8b57));
table.put("seashell", new Color(0xfff5ee));
table.put("sienna", new Color(0xa0522d));
table.put("silver", new Color(0xc0c0c0));
table.put("skyblue", new Color(0x87ceeb));
table.put("slateblue", new Color(0x6a5acd));
table.put("slategray", new Color(0x708090));
table.put("snow", new Color(0xfffafa));
table.put("springgreen", new Color(0x00ff7f));
table.put("steelblue", new Color(0x4682b4));
table.put("tan", new Color(0xd2b48c));
table.put("teal", new Color(0x008080));
table.put("thistle", new Color(0xd8bfd8));
table.put("tomato", new Color(0xff6347));
table.put("turquoise", new Color(0x40e0d0));
table.put("violet", new Color(0xee82ee));
table.put("violetred", new Color(0xd02090));
table.put("wheat", new Color(0xf5deb3));
table.put("white", new Color(0xffffff));
table.put("whitesmoke", new Color(0xf5f5f5));
table.put("yellow", new Color(0xffff00));
table.put("yellowgreen", new Color(0x9acd32));
colorTable = Collections.unmodifiableMap(table);
}
static ColorTable singleton = new ColorTable();
/** Creates a new instance of ColorTable */
protected ColorTable() {
// buildColorList();
}
static public ColorTable instance() { return singleton; }
public Color lookupColor(String name) {
return colorTable.get(name.toLowerCase());
}
public static Color parseColor(String val)
{
Color retVal = null;
if ("".equals(val))
{
return null;
}
if (val.charAt(0) == '#')
{
String hexStrn = val.substring(1);
if (hexStrn.length() == 3)
{
hexStrn = "" + hexStrn.charAt(0) + hexStrn.charAt(0) + hexStrn.charAt(1) + hexStrn.charAt(1) + hexStrn.charAt(2) + hexStrn.charAt(2);
}
int hexVal = parseHex(hexStrn);
retVal = new Color(hexVal);
}
else
{
final String number = "\\s*(((\\d+)(\\.\\d*)?)|(\\.\\d+))(%)?\\s*";
final Matcher rgbMatch = Pattern.compile("rgb\\(" + number + "," + number + "," + number + "\\)", Pattern.CASE_INSENSITIVE).matcher("");
rgbMatch.reset(val);
if (rgbMatch.matches())
{
float rr = Float.parseFloat(rgbMatch.group(1));
float gg = Float.parseFloat(rgbMatch.group(7));
float bb = Float.parseFloat(rgbMatch.group(13));
rr /= "%".equals(rgbMatch.group(6)) ? 100 : 255;
gg /= "%".equals(rgbMatch.group(12)) ? 100 : 255;
bb /= "%".equals(rgbMatch.group(18)) ? 100 : 255;
retVal = new Color(rr, gg, bb);
}
else
{
Color lookupCol = ColorTable.instance().lookupColor(val);
if (lookupCol != null) retVal = lookupCol;
}
}
return retVal;
}
public static int parseHex(String val)
{
int retVal = 0;
for (int i = 0; i < val.length(); i++)
{
retVal <<= 4;
char ch = val.charAt(i);
if (ch >= '0' && ch <= '9')
{
retVal |= ch - '0';
}
else if (ch >= 'a' && ch <= 'z')
{
retVal |= ch - 'a' + 10;
}
else if (ch >= 'A' && ch <= 'Z')
{
retVal |= ch - 'A' + 10;
}
else throw new RuntimeException();
}
return retVal;
}
}

Some files were not shown because too many files have changed in this diff Show more