diff --git a/graphics-chart/src/main/java/org/xbib/graphics/chart/QuickChart.java b/graphics-chart/src/main/java/org/xbib/graphics/chart/QuickChart.java index c6e445c..0bfb566 100644 --- a/graphics-chart/src/main/java/org/xbib/graphics/chart/QuickChart.java +++ b/graphics-chart/src/main/java/org/xbib/graphics/chart/QuickChart.java @@ -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 xData, - List yData) { - XYChart chart = new XYChart(WIDTH, HEIGHT); + List yData, + int width, + int height) { + XYChart chart = new XYChart(width, height); chart.setTitle(chartTitle); chart.setXAxisTitle(xTitle); chart.setYAxisTitle(yTitle); diff --git a/graphics-chart/src/test/java/org/xbib/graphics/chart/demo/QuickChartTest.java b/graphics-chart/src/test/java/org/xbib/graphics/chart/demo/QuickChartTest.java index e7eb2e0..6b67d7b 100644 --- a/graphics-chart/src/test/java/org/xbib/graphics/chart/demo/QuickChartTest.java +++ b/graphics-chart/src/test/java/org/xbib/graphics/chart/demo/QuickChartTest.java @@ -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); } diff --git a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/elements/ChartElement.java b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/elements/ChartElement.java index a4a9e03..7f0b658 100644 --- a/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/elements/ChartElement.java +++ b/graphics-pdfbox-layout/src/main/java/org/xbib/graphics/pdfbox/layout/elements/ChartElement.java @@ -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) { diff --git a/graphics-pdfbox-layout/src/test/resources/org/xbib/graphics/pdfbox/layout/test/script/deckblatt.json b/graphics-pdfbox-layout/src/test/resources/org/xbib/graphics/pdfbox/layout/test/script/deckblatt.json index b8067cd..64ec5f9 100644 --- a/graphics-pdfbox-layout/src/test/resources/org/xbib/graphics/pdfbox/layout/test/script/deckblatt.json +++ b/graphics-pdfbox-layout/src/test/resources/org/xbib/graphics/pdfbox/layout/test/script/deckblatt.json @@ -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 ] } ] } diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/A.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/A.java new file mode 100644 index 0000000..6b52266 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/A.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/BufferPainter.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/BufferPainter.java new file mode 100644 index 0000000..d073b55 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/BufferPainter.java @@ -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 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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Circle.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Circle.java new file mode 100644 index 0000000..79235e3 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Circle.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/ClipPath.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/ClipPath.java new file mode 100644 index 0000000..264dc27 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/ClipPath.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Defs.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Defs.java new file mode 100644 index 0000000..f90eb93 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Defs.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Desc.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Desc.java new file mode 100644 index 0000000..d3c6279 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Desc.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Ellipse.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Ellipse.java new file mode 100644 index 0000000..5098188 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Ellipse.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/FeDistantLight.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/FeDistantLight.java new file mode 100644 index 0000000..8a08dd4 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/FeDistantLight.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/FeGaussianBlur.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/FeGaussianBlur.java new file mode 100644 index 0000000..922ca70 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/FeGaussianBlur.java @@ -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 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); + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/FeLight.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/FeLight.java new file mode 100644 index 0000000..919408c --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/FeLight.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/FePointLight.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/FePointLight.java new file mode 100644 index 0000000..d666cf5 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/FePointLight.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/FeSpotLight.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/FeSpotLight.java new file mode 100644 index 0000000..ec1023f --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/FeSpotLight.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/FillElement.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/FillElement.java new file mode 100644 index 0000000..8e83ab9 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/FillElement.java @@ -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 Mark McKay + */ +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); +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Filter.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Filter.java new file mode 100644 index 0000000..b8e6cf5 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Filter.java @@ -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 Mark McKay + */ +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 = 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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/FilterEffects.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/FilterEffects.java new file mode 100644 index 0000000..def75af --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/FilterEffects.java @@ -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 Mark McKay + */ +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 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; + } + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Font.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Font.java new file mode 100644 index 0000000..ade2c44 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Font.java @@ -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 Mark McKay + */ +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 glyphs = new HashMap(); + + /** + * 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; + */ + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/FontFace.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/FontFace.java new file mode 100644 index 0000000..a65bb59 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/FontFace.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Glyph.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Glyph.java new file mode 100644 index 0000000..0bed322 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Glyph.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Gradient.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Gradient.java new file mode 100644 index 0000000..279a1b7 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Gradient.java @@ -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 Mark McKay + */ +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 stops = new ArrayList(); + 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 stopList = new ArrayList(stops); + stopList.sort(new Comparator(){ + 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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Group.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Group.java new file mode 100644 index 0000000..670d54d --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Group.java @@ -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 Mark McKay + */ +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> 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> 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 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 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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Hkern.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Hkern.java new file mode 100644 index 0000000..0a9a5e6 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Hkern.java @@ -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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/ImageSVG.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/ImageSVG.java new file mode 100644 index 0000000..1056342 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/ImageSVG.java @@ -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 Mark McKay + */ +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> retVec) throws SVGException + { + if (getBoundingBox().contains(point)) + { + retVec.add(getPath(null)); + } + } + + @Override + protected void doPick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List> 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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Line.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Line.java new file mode 100644 index 0000000..0c6d7ea --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Line.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/LinearGradient.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/LinearGradient.java new file mode 100644 index 0000000..af3e90d --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/LinearGradient.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Marker.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Marker.java new file mode 100644 index 0000000..2f881cb --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Marker.java @@ -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 markerList = new ArrayList(); + 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 getMarkerList() + { + return markerList; + } + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Mask.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Mask.java new file mode 100644 index 0000000..2bedbdb --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Mask.java @@ -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> retVec) + { + } + + @Override + void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List> retVec) + { + } + + public void pickElement(Point2D point, boolean boundingBox, + List> 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> 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); + } + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Metadata.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Metadata.java new file mode 100644 index 0000000..ff00644 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Metadata.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/MissingGlyph.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/MissingGlyph.java new file mode 100644 index 0000000..ac00e32 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/MissingGlyph.java @@ -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 Mark McKay + */ +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 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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Path.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Path.java new file mode 100644 index 0000000..cec1794 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Path.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/PatternSVG.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/PatternSVG.java new file mode 100644 index 0000000..49fd631 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/PatternSVG.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Polygon.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Polygon.java new file mode 100644 index 0000000..6aba981 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Polygon.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Polyline.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Polyline.java new file mode 100644 index 0000000..a0fc309 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Polyline.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/RadialGradient.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/RadialGradient.java new file mode 100644 index 0000000..11bb0a0 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/RadialGradient.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Rect.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Rect.java new file mode 100644 index 0000000..67ef935 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Rect.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/RenderableElement.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/RenderableElement.java new file mode 100644 index 0000000..e0278f3 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/RenderableElement.java @@ -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 Mark McKay + */ +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> 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> retVec) throws SVGException; + + void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List> 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> 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); + } + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGCache.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGCache.java new file mode 100644 index 0000000..7ca2439 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGCache.java @@ -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; + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGConst.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGConst.java new file mode 100644 index 0000000..81e20e8 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGConst.java @@ -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"; +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGDiagram.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGDiagram.java new file mode 100644 index 0000000..1280230 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGDiagram.java @@ -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 Mark McKay + */ +public class SVGDiagram implements Serializable +{ + public static final long serialVersionUID = 0; + + //Indexes elements within this SVG diagram + final HashMap idMap = new HashMap(); + + 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> pick(Point2D point, List> retVec) throws SVGException + { + return pick(point, false, retVec); + } + + public List> pick(Point2D point, boolean boundingBox, List> retVec) throws SVGException + { + if (retVec == null) + { + retVec = new ArrayList>(); + } + + root.pick(point, boundingBox, retVec); + + return retVec; + } + + public List> pick(Rectangle2D pickArea, List> retVec) throws SVGException + { + return pick(pickArea, false, retVec); + } + + public List> pick(Rectangle2D pickArea, boolean boundingBox, List> retVec) throws SVGException + { + if (retVec == null) + { + retVec = new ArrayList>(); + } + + 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); + } + } + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGDisplayPanel.form b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGDisplayPanel.form new file mode 100644 index 0000000..226f748 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGDisplayPanel.form @@ -0,0 +1,20 @@ + + +
+ + + + + + + + + + + + + + + + + diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGDisplayPanel.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGDisplayPanel.java new file mode 100644 index 0000000..6dea89b --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGDisplayPanel.java @@ -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 Mark McKay + */ +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. + */ + // //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); + } + }); + + }// //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 + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGElement.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGElement.java new file mode 100644 index 0000000..7df52e4 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGElement.java @@ -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 Mark McKay + */ +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 children = new ArrayList(); + protected String id = null; + /** + * CSS class. Used for applying style sheet information. + */ + protected String cssClass = null; + /** + * Styles defined for this elemnt via the style attribute. + */ + protected final HashMap inlineStyles = new HashMap(); + /** + * Presentation attributes set for this element. Ie, any attribute other + * than the style attribute. + */ + protected final HashMap presAttribs = new HashMap(); + /** + * 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 getPath(List retVec) + { + if (retVec == null) + { + retVec = new ArrayList(); + } + + 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 getChildren(List retVec) + { + if (retVec == null) + { + retVec = new ArrayList(); + } + + 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 getInlineAttributes() + { + return inlineStyles.keySet(); + } + + /** + * @return a set of Strings that correspond to XML attributes on this element + */ + public Set 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 contexts = new LinkedList(); + + /** + * 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 termList = new LinkedList(); + while (matchWord.find()) + { + termList.add(matchWord.group()); + } + + + double[] terms = new double[termList.size()]; + Iterator 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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGElementException.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGElementException.java new file mode 100644 index 0000000..0c760d6 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGElementException.java @@ -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 SVGException without detail message. + * @param element + */ + public SVGElementException(SVGElement element) + { + this(element, null, null); + } + + + /** + * Constructs an instance of SVGException 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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGException.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGException.java new file mode 100644 index 0000000..1dfb776 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGException.java @@ -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 SVGException without detail message. + */ + public SVGException() + { + } + + + /** + * Constructs an instance of SVGException 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); + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGLoader.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGLoader.java new file mode 100644 index 0000000..107a539 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGLoader.java @@ -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 Mark McKay + */ +public class SVGLoader extends DefaultHandler +{ + final HashMap> nodeClasses = new HashMap>(); + //final HashMap attribClasses = new HashMap(); + final LinkedList buildStack = new LinkedList(); + + final HashSet ignoreClasses = new HashSet(); + + 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; } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGLoaderHelper.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGLoaderHelper.java new file mode 100644 index 0000000..b28775d --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGLoaderHelper.java @@ -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; + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGParseException.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGParseException.java new file mode 100644 index 0000000..77ca7f6 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGParseException.java @@ -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 SVGException without detail message. + */ + public SVGParseException() + { + } + + + /** + * Constructs an instance of SVGException 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); + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGRoot.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGRoot.java new file mode 100644 index 0000000..3fa9544 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGRoot.java @@ -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 Mark McKay + */ +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> 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> 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; + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGUniverse.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGUniverse.java new file mode 100644 index 0000000..ace8387 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/SVGUniverse.java @@ -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 Mark McKay + */ +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 svgSalamander. + */ + final HashMap loadedDocs = new HashMap(); + final HashMap loadedFonts = new HashMap(); + final HashMap> loadedImages = new HashMap>(); + 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, 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 ref = new SoftReference(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 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(img); + } else + { + BufferedImage img = ImageIO.read(imageURL); + ref = new SoftReference(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 ref = (SoftReference) 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(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 -

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.

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.

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

If a name does not start with the character '/', + * it will be automatically prefixed to it.

+ * @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 threadSAXParser = new ThreadLocal(); + + 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 getLoadedDocumentURIs() + { + return new ArrayList(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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/ShapeElement.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/ShapeElement.java new file mode 100644 index 0000000..9b26018 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/ShapeElement.java @@ -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 Mark McKay + */ +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> 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> 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 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; + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Stop.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Stop.java new file mode 100644 index 0000000..e60eba4 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Stop.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Style.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Style.java new file mode 100644 index 0000000..2a8e416 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Style.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Symbol.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Symbol.java new file mode 100644 index 0000000..3efb8bc --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Symbol.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Text.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Text.java new file mode 100644 index 0000000..4642cb6 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Text.java @@ -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 Mark McKay + */ +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 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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Title.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Title.java new file mode 100644 index 0000000..26b89e6 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Title.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/TransformableElement.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/TransformableElement.java new file mode 100644 index 0000000..5b3ca12 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/TransformableElement.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Tspan.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Tspan.java new file mode 100644 index 0000000..2f7f875 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Tspan.java @@ -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 Mark McKay + */ +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 content = new ArrayList<>(); + protected final ArrayList 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 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; + } + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/Use.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/Use.java new file mode 100644 index 0000000..8e9e709 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/Use.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/MainFrame.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/MainFrame.java new file mode 100644 index 0000000..37431df --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/MainFrame.java @@ -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 + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/PlayerDialog.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/PlayerDialog.java new file mode 100644 index 0000000..2196919 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/PlayerDialog.java @@ -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. + */ + // //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(); + }// //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 + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/PlayerThread.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/PlayerThread.java new file mode 100644 index 0000000..845ea6a --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/PlayerThread.java @@ -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 listeners = new HashSet(); + + 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); + } + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/PlayerThreadListener.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/PlayerThreadListener.java new file mode 100644 index 0000000..86f97c2 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/PlayerThreadListener.java @@ -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); +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/SVGPlayer.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/SVGPlayer.java new file mode 100644 index 0000000..8b2b309 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/SVGPlayer.java @@ -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 Mark McKay + */ +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> 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 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. + */ + // //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(); + }// //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 + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/SVGViewer.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/SVGViewer.java new file mode 100644 index 0000000..981d534 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/SVGViewer.java @@ -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 Mark McKay + */ +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. + */ + // //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(); + }// //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> 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 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 + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/VersionDialog.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/VersionDialog.java new file mode 100644 index 0000000..30438cc --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/VersionDialog.java @@ -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. + */ + // //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(); + } + // //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 + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/ProportionalLayoutPanel.form b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/ProportionalLayoutPanel.form new file mode 100644 index 0000000..87e8627 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/ProportionalLayoutPanel.form @@ -0,0 +1,34 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/ProportionalLayoutPanel.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/ProportionalLayoutPanel.java new file mode 100644 index 0000000..a7ad78a --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/ProportionalLayoutPanel.java @@ -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. + */ + // //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); + + } + // //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 + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/SVGIcon.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/SVGIcon.java new file mode 100644 index 0000000..a95c097 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/SVGIcon.java @@ -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); + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/SVGPanel.form b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/SVGPanel.form new file mode 100644 index 0000000..61a84d5 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/SVGPanel.form @@ -0,0 +1,17 @@ + + +
+ + + + + + + + + + + + + + diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/SVGPanel.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/SVGPanel.java new file mode 100644 index 0000000..29662e3 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/beans/SVGPanel.java @@ -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. + */ + // //GEN-BEGIN:initComponents + private void initComponents() + { + + setLayout(new java.awt.BorderLayout()); + + } + // //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables + + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/data/Handler.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/data/Handler.java new file mode 100644 index 0000000..c517903 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/data/Handler.java @@ -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); + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/app/data/HandlerFactory.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/data/HandlerFactory.java new file mode 100644 index 0000000..1f1cd8d --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/app/data/HandlerFactory.java @@ -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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/composite/AdobeComposite.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/composite/AdobeComposite.java new file mode 100644 index 0000000..9dbdc5b --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/composite/AdobeComposite.java @@ -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 Mark McKay + */ +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); + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/composite/AdobeCompositeContext.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/composite/AdobeCompositeContext.java new file mode 100644 index 0000000..fa63245 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/composite/AdobeCompositeContext.java @@ -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 Mark McKay + */ +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() { + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Arc.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Arc.java new file mode 100644 index 0000000..7028fe8 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Arc.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/BuildHistory.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/BuildHistory.java new file mode 100644 index 0000000..f9d8366 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/BuildHistory.java @@ -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 Mark McKay + */ +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; +// } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Cubic.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Cubic.java new file mode 100644 index 0000000..ca0207b --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Cubic.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/CubicSmooth.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/CubicSmooth.java new file mode 100644 index 0000000..f97971b --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/CubicSmooth.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Horizontal.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Horizontal.java new file mode 100644 index 0000000..fdcd179 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Horizontal.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/LineTo.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/LineTo.java new file mode 100644 index 0000000..cb16993 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/LineTo.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/MoveTo.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/MoveTo.java new file mode 100644 index 0000000..68f9313 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/MoveTo.java @@ -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 Mark McKay + */ +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; + } + + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/PathCommand.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/PathCommand.java new file mode 100644 index 0000000..72167d2 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/PathCommand.java @@ -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 Mark McKay + */ +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(); +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/PathParser.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/PathParser.java new file mode 100644 index 0000000..d38a4cf --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/PathParser.java @@ -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 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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/PathUtil.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/PathUtil.java new file mode 100644 index 0000000..f8fa707 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/PathUtil.java @@ -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(); + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Quadratic.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Quadratic.java new file mode 100644 index 0000000..d7e4266 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Quadratic.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/QuadraticSmooth.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/QuadraticSmooth.java new file mode 100644 index 0000000..9eb2d2d --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/QuadraticSmooth.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Terminal.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Terminal.java new file mode 100644 index 0000000..f392ff1 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Terminal.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Vertical.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Vertical.java new file mode 100644 index 0000000..e713f44 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pathcmd/Vertical.java @@ -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 Mark McKay + */ +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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pattern/PatternPaint.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pattern/PatternPaint.java new file mode 100644 index 0000000..57f0b7f --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pattern/PatternPaint.java @@ -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 Mark McKay + */ +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(); + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/pattern/PatternPaintContext.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/pattern/PatternPaintContext.java new file mode 100644 index 0000000..b0b211d --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/pattern/PatternPaintContext.java @@ -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 Mark McKay + */ +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)); + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/util/Base64Consts.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/util/Base64Consts.java new file mode 100644 index 0000000..84aa83f --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/util/Base64Consts.java @@ -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+/"; + + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/util/Base64InputStream.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/util/Base64InputStream.java new file mode 100644 index 0000000..4652084 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/util/Base64InputStream.java @@ -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 lookup64 = new HashMap(); + 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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/util/Base64OutputStream.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/util/Base64OutputStream.java new file mode 100644 index 0000000..9c4a5d1 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/util/Base64OutputStream.java @@ -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; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/util/FontSystem.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/util/FontSystem.java new file mode 100644 index 0000000..45bf356 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/util/FontSystem.java @@ -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 glyphCache = new HashMap<>(); + + static HashSet 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; + } + + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/util/FontUtil.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/util/FontUtil.java new file mode 100644 index 0000000..3a7ad39 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/util/FontUtil.java @@ -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; + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/util/TextBuilder.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/util/TextBuilder.java new file mode 100644 index 0000000..6d2ea0f --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/util/TextBuilder.java @@ -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 +{ + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/ColorTable.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/ColorTable.java new file mode 100644 index 0000000..edb6df6 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/ColorTable.java @@ -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 Mark McKay + */ +public class ColorTable +{ + + static final Map colorTable; + static { + HashMap table = new HashMap(); + + //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; + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/NumberWithUnits.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/NumberWithUnits.java new file mode 100644 index 0000000..bc46af3 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/NumberWithUnits.java @@ -0,0 +1,160 @@ +/* + * 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, 2:43 PM + */ + +package org.xbib.graphics.svg.xml; + +import java.io.Serializable; + +/** + * @author Mark McKay + * @author Mark McKay + */ +public class NumberWithUnits implements Serializable +{ + public static final long serialVersionUID = 0; + + public static final int UT_UNITLESS = 0; + public static final int UT_PX = 1; //Pixels + public static final int UT_CM = 2; //Centimeters + public static final int UT_MM = 3; //Millimeters + public static final int UT_IN = 4; //Inches + public static final int UT_EM = 5; //Default font height + public static final int UT_EX = 6; //Height of character 'x' in default font + public static final int UT_PT = 7; //Points - 1/72 of an inch + public static final int UT_PC = 8; //Picas - 1/6 of an inch + public static final int UT_PERCENT = 9; //Percent - relative width + + float value = 0f; + int unitType = UT_UNITLESS; + + /** Creates a new instance of NumberWithUnits */ + public NumberWithUnits() + { + } + + public NumberWithUnits(String value) + { + set(value); + } + + public NumberWithUnits(float value, int unitType) + { + this.value = value; + this.unitType = unitType; + } + + public float getValue() { return value; } + public int getUnits() { return unitType; } + + public void set(String value) + { + this.value = XMLParseUtil.findFloat(value); + unitType = UT_UNITLESS; + + if (value.indexOf("px") != -1) { unitType = UT_PX; return; } + if (value.indexOf("cm") != -1) { unitType = UT_CM; return; } + if (value.indexOf("mm") != -1) { unitType = UT_MM; return; } + if (value.indexOf("in") != -1) { unitType = UT_IN; return; } + if (value.indexOf("em") != -1) { unitType = UT_EM; return; } + if (value.indexOf("ex") != -1) { unitType = UT_EX; return; } + if (value.indexOf("pt") != -1) { unitType = UT_PT; return; } + if (value.indexOf("pc") != -1) { unitType = UT_PC; return; } + if (value.indexOf("%") != -1) { unitType = UT_PERCENT; return; } + } + + public static String unitsAsString(int unitIdx) + { + switch (unitIdx) + { + default: + return ""; + case UT_PX: + return "px"; + case UT_CM: + return "cm"; + case UT_MM: + return "mm"; + case UT_IN: + return "in"; + case UT_EM: + return "em"; + case UT_EX: + return "ex"; + case UT_PT: + return "pt"; + case UT_PC: + return "pc"; + case UT_PERCENT: + return "%"; + } + } + + @Override + public String toString() + { + return "" + value + unitsAsString(unitType); + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final NumberWithUnits other = (NumberWithUnits) obj; + if (Float.floatToIntBits(this.value) != Float.floatToIntBits(other.value)) { + return false; + } + if (this.unitType != other.unitType) { + return false; + } + return true; + } + + @Override + public int hashCode() + { + int hash = 5; + hash = 37 * hash + Float.floatToIntBits(this.value); + hash = 37 * hash + this.unitType; + return hash; + } + + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/ReadableXMLElement.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/ReadableXMLElement.java new file mode 100644 index 0000000..bf7c0e8 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/ReadableXMLElement.java @@ -0,0 +1,55 @@ +/* + * 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 1, 2003, 1:46 AM + */ + +package org.xbib.graphics.svg.xml; + +import org.w3c.dom.*; +import java.net.*; + +/** + * @author Mark McKay + * @author Mark McKay + */ +public interface ReadableXMLElement { + + /** + * Initializes this element from the passed DOM tree. + * @param root - DOM tree to build from + * @param docRoot - URL of the document this DOM tree was created from + */ + public void read(Element root, URL docRoot); + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/StyleAttribute.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/StyleAttribute.java new file mode 100644 index 0000000..57649ea --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/StyleAttribute.java @@ -0,0 +1,294 @@ +package org.xbib.graphics.svg.xml; + +import org.xbib.graphics.svg.SVGConst; + +import java.awt.Color; +import java.awt.HeadlessException; +import java.awt.Toolkit; +import java.io.File; +import java.io.Serializable; +import java.net.URI; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class StyleAttribute implements Serializable +{ + public static final long serialVersionUID = 0; + + static final Pattern patternUrl = Pattern.compile("\\s*url\\((.*)\\)\\s*"); + + static final Matcher matchFpNumUnits = Pattern.compile("\\s*([-+]?((\\d*\\.\\d+)|(\\d+))([-+]?[eE]\\d+)?)\\s*(px|cm|mm|in|pc|pt|em|ex)\\s*").matcher(""); + + String name; + String stringValue; + + boolean colorCompatable = false; + boolean urlCompatable = false; + + /** Creates a new instance of StyleAttribute */ + public StyleAttribute() + { + this(null, null); + } + + public StyleAttribute(String name) + { + this.name = name; + stringValue = null; + } + + public StyleAttribute(String name, String stringValue) + { + this.name = name; + this.stringValue = stringValue; + } + + public String getName() { + return name; + } + + public StyleAttribute setName(String name) + { + this.name = name; + return this; + } + + public String getStringValue() + { + return stringValue; + } + + public String[] getStringList() + { + return XMLParseUtil.parseStringList(stringValue); + } + + public void setStringValue(String value) + { + stringValue = value; + } + + public boolean getBooleanValue() { + return stringValue.toLowerCase().equals("true"); + } + + public int getIntValue() { + return XMLParseUtil.findInt(stringValue); + } + + public int[] getIntList() { + return XMLParseUtil.parseIntList(stringValue); + } + + public double getDoubleValue() { + return XMLParseUtil.findDouble(stringValue); + } + + public double[] getDoubleList() { + return XMLParseUtil.parseDoubleList(stringValue); + } + + public float getFloatValue() { + return XMLParseUtil.findFloat(stringValue); + } + + public float[] getFloatList() { + return XMLParseUtil.parseFloatList(stringValue); + } + + public float getRatioValue() { + return (float)XMLParseUtil.parseRatio(stringValue); +// try { return Float.parseFloat(stringValue); } +// catch (Exception e) {} +// return 0f; + } + + public String getUnits() { + matchFpNumUnits.reset(stringValue); + if (!matchFpNumUnits.matches()) return null; + return matchFpNumUnits.group(6); + } + + public NumberWithUnits getNumberWithUnits() { + return XMLParseUtil.parseNumberWithUnits(stringValue); + } + + public float getFloatValueWithUnits() + { + NumberWithUnits number = getNumberWithUnits(); + return convertUnitsToPixels(number.getUnits(), number.getValue()); + } + + public float[] getFloatListWithUnits() + { + String[] values = getStringList(); + float[] result = new float[values.length]; + for (int i = 0; i < result.length; i++) + { + NumberWithUnits number = XMLParseUtil.parseNumberWithUnits(stringValue); + result[i] = convertUnitsToPixels(number.getUnits(), number.getValue()); + } + return result; + } + + static public float convertUnitsToPixels(int unitType, float value) + { + if (unitType == NumberWithUnits.UT_UNITLESS || unitType == NumberWithUnits.UT_PERCENT) + { + return value; + } + + float pixPerInch; + try + { + pixPerInch = (float)Toolkit.getDefaultToolkit().getScreenResolution(); + } + catch (HeadlessException ex) + { + //default to 72 dpi + pixPerInch = 72; + } + final float inchesPerCm = .3936f; + + switch (unitType) + { + case NumberWithUnits.UT_IN: + return value * pixPerInch; + case NumberWithUnits.UT_CM: + return value * inchesPerCm * pixPerInch; + case NumberWithUnits.UT_MM: + return value * .1f * inchesPerCm * pixPerInch; + case NumberWithUnits.UT_PT: + return value * (1f / 72f) * pixPerInch; + case NumberWithUnits.UT_PC: + return value * (1f / 6f) * pixPerInch; + } + + return value; + } + + public Color getColorValue() + { + return ColorTable.parseColor(stringValue); + } + + public String parseURLFn() + { + Matcher matchUrl = patternUrl.matcher(stringValue); + if (!matchUrl.matches()) + { + return null; + } + return matchUrl.group(1); + } + + public URL getURLValue(URL docRoot) + { + String fragment = parseURLFn(); + if (fragment == null) return null; + try { + return new URL(docRoot, fragment); + } + catch (Exception e) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); + return null; + } + } + + public URL getURLValue(URI docRoot) + { + String fragment = parseURLFn(); + if (fragment == null) return null; + try { + URI ref = docRoot.resolve(fragment); + return ref.toURL(); + } + catch (Exception e) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); + return null; + } + } + + public URI getURIValue() + { + return getURIValue(null); + } + + /** + * Parse this sytle attribute as a URL and return it in URI form resolved + * against the passed base. + * + * @param base - URI to resolve against. If null, will return value without + * attempting to resolve it. + */ + public URI getURIValue(URI base) + { + try { + String fragment = parseURLFn(); + if (fragment == null) fragment = stringValue.replaceAll("\\s+", ""); + if (fragment == null) return null; + + //====================== + //This gets around a bug in the 1.5.0 JDK + if (Pattern.matches("[a-zA-Z]:!\\\\.*", fragment)) + { + File file = new File(fragment); + return file.toURI(); + } + //====================== + + //[scheme:]scheme-specific-part[#fragment] + + URI uriFrag = new URI(fragment); + if (uriFrag.isAbsolute()) + { + //Has scheme + return uriFrag; + } + + if (base == null) return uriFrag; + + URI relBase = new URI(null, base.getSchemeSpecificPart(), null); + URI relUri; + if (relBase.isOpaque()) + { + relUri = new URI(null, base.getSchemeSpecificPart(), uriFrag.getFragment()); + } + else + { + relUri = relBase.resolve(uriFrag); + } + return new URI(base.getScheme() + ":" + relUri); + } + catch (Exception e) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); + return null; + } + } + + public static void main(String[] args) + { + try + { + URI uri = new URI("jar:http://www.kitfox.com/jackal/jackal.jar!/res/doc/about.svg"); + uri = uri.resolve("#myFragment"); + + System.err.println(uri.toString()); + + uri = new URI("http://www.kitfox.com/jackal/jackal.html"); + uri = uri.resolve("#myFragment"); + + System.err.println(uri.toString()); + } + catch (Exception e) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); + } + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/StyleSheet.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/StyleSheet.java new file mode 100644 index 0000000..b2f6eeb --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/StyleSheet.java @@ -0,0 +1,67 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.xbib.graphics.svg.xml; + +import org.xbib.graphics.svg.SVGConst; +import java.util.HashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author kitfox + */ +public class StyleSheet +{ + HashMap ruleMap = new HashMap(); + + public static StyleSheet parseSheet(String src) + { + //Implement CS parser later + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, + "CSS parser not implemented yet"); + return null; + } + + public void addStyleRule(StyleSheetRule rule, String value) + { + ruleMap.put(rule, value); + } + + public boolean getStyle(StyleAttribute attrib, String tagName, String cssClass) + { + StyleSheetRule rule = new StyleSheetRule(attrib.getName(), tagName, cssClass); + String value = (String)ruleMap.get(rule); + + if (value != null) + { + attrib.setStringValue(value); + return true; + } + + //Try again using just class name + rule = new StyleSheetRule(attrib.getName(), null, cssClass); + value = (String)ruleMap.get(rule); + + if (value != null) + { + attrib.setStringValue(value); + return true; + } + + //Try again using just tag name + rule = new StyleSheetRule(attrib.getName(), tagName, null); + value = (String)ruleMap.get(rule); + + if (value != null) + { + attrib.setStringValue(value); + return true; + } + + return false; + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/StyleSheetRule.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/StyleSheetRule.java new file mode 100644 index 0000000..b2763aa --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/StyleSheetRule.java @@ -0,0 +1,61 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.xbib.graphics.svg.xml; + +/** + * + * @author kitfox + */ +public class StyleSheetRule +{ + final String styleName; + final String tag; + final String className; + + public StyleSheetRule(String styleName, String tag, String className) + { + this.styleName = styleName; + this.tag = tag; + this.className = className; + } + + @Override + public int hashCode() + { + int hash = 7; + hash = 13 * hash + (this.styleName != null ? this.styleName.hashCode() : 0); + hash = 13 * hash + (this.tag != null ? this.tag.hashCode() : 0); + hash = 13 * hash + (this.className != null ? this.className.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final StyleSheetRule other = (StyleSheetRule) obj; + if ((this.styleName == null) ? (other.styleName != null) : !this.styleName.equals(other.styleName)) + { + return false; + } + if ((this.tag == null) ? (other.tag != null) : !this.tag.equals(other.tag)) + { + return false; + } + if ((this.className == null) ? (other.className != null) : !this.className.equals(other.className)) + { + return false; + } + return true; + } + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/WritableXMLElement.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/WritableXMLElement.java new file mode 100644 index 0000000..0ac2e08 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/WritableXMLElement.java @@ -0,0 +1,52 @@ +/* + * 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 1, 2003, 1:46 AM + */ + +package org.xbib.graphics.svg.xml; + +/** + * @author Mark McKay + * @author Mark McKay + */ +public interface WritableXMLElement { + + /** + * Initializes this element from the passed DOM tree. + * @param root - DOM tree to build from + * @param docRoot - URL of the document this DOM tree was created from + */ +// public void write(Element root, URL docRoot); + +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/XMLParseUtil.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/XMLParseUtil.java new file mode 100644 index 0000000..0002415 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/XMLParseUtil.java @@ -0,0 +1,800 @@ +package org.xbib.graphics.svg.xml; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.xbib.graphics.svg.SVGConst; +import java.awt.Toolkit; +import java.lang.reflect.Array; +import java.net.URL; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class XMLParseUtil +{ + static final Matcher fpMatch = Pattern.compile("([-+]?((\\d*\\.\\d+)|(\\d+))([eE][+-]?\\d+)?)(\\%|in|cm|mm|pt|pc|px|em|ex)?").matcher(""); + static final Matcher intMatch = Pattern.compile("[-+]?\\d+").matcher(""); + static final Matcher quoteMatch = Pattern.compile("^'|'$").matcher(""); + + /** Creates a new instance of XMLParseUtil */ + private XMLParseUtil() + { + } + + /** + * Scans the tag's children and returns the first text element found + */ + public static String getTagText(Element ele) + { + NodeList nl = ele.getChildNodes(); + int size = nl.getLength(); + + Node node = null; + int i = 0; + for (; i < size; i++) + { + node = nl.item(i); + if (node instanceof Text) break; + } + if (i == size || node == null) return null; + + return ((Text)node).getData(); + } + + /** + * Returns the first node that is a direct child of root with the corresponding + * name. Does not search children of children. + */ + public static Element getFirstChild(Element root, String name) + { + NodeList nl = root.getChildNodes(); + int size = nl.getLength(); + for (int i = 0; i < size; i++) + { + Node node = nl.item(i); + if (!(node instanceof Element)) continue; + Element ele = (Element)node; + if (ele.getTagName().equals(name)) return ele; + } + + return null; + } + + public static String[] parseStringList(String list) + { +// final Pattern patWs = Pattern.compile("\\s+"); + final Matcher matchWs = Pattern.compile("[^\\s]+").matcher(""); + matchWs.reset(list); + + LinkedList matchList = new LinkedList(); + while (matchWs.find()) + { + matchList.add(matchWs.group()); + } + + String[] retArr = new String[matchList.size()]; + return (String[])matchList.toArray(retArr); + } + + public static boolean isDouble(String val) + { + fpMatch.reset(val); + return fpMatch.matches(); + } + + public static double parseDouble(String val) + { + /* + if (val == null) return 0.0; + + double retVal = 0.0; + try + { retVal = Double.parseDouble(val); } + catch (Exception e) + {} + return retVal; + */ + return findDouble(val); + } + + /** + * Searches the given string for the first floating point number it contains, + * parses and returns it. + */ + public synchronized static double findDouble(String val) + { + if (val == null) return 0; + + fpMatch.reset(val); + try + { + if (!fpMatch.find()) return 0; + } + catch (StringIndexOutOfBoundsException e) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, + "XMLParseUtil: regex parse problem: '" + val + "'", e); + } + + val = fpMatch.group(1); + //System.err.println("Parsing " + val); + + double retVal = 0; + try + { + retVal = Double.parseDouble(val); + + float pixPerInch; + try { + pixPerInch = (float)Toolkit.getDefaultToolkit().getScreenResolution(); + } + catch (NoClassDefFoundError err) + { + //Default value for headless X servers + pixPerInch = 72; + } + final float inchesPerCm = .3936f; + final String units = fpMatch.group(6); + + if ("%".equals(units)) retVal /= 100; + else if ("in".equals(units)) + { + retVal *= pixPerInch; + } + else if ("cm".equals(units)) + { + retVal *= inchesPerCm * pixPerInch; + } + else if ("mm".equals(units)) + { + retVal *= inchesPerCm * pixPerInch * .1f; + } + else if ("pt".equals(units)) + { + retVal *= (1f / 72f) * pixPerInch; + } + else if ("pc".equals(units)) + { + retVal *= (1f / 6f) * pixPerInch; + } + } + catch (Exception e) + {} + return retVal; + } + + /** + * Scans an input string for double values. For each value found, places + * in a list. This method regards any characters not part of a floating + * point value to be seperators. Thus this will parse whitespace seperated, + * comma seperated, and many other separation schemes correctly. + */ + public synchronized static double[] parseDoubleList(String list) + { + if (list == null) return null; + + fpMatch.reset(list); + + LinkedList doubList = new LinkedList(); + while (fpMatch.find()) + { + String val = fpMatch.group(1); + doubList.add(Double.valueOf(val)); + } + + double[] retArr = new double[doubList.size()]; + Iterator it = doubList.iterator(); + int idx = 0; + while (it.hasNext()) + { + retArr[idx++] = ((Double)it.next()).doubleValue(); + } + + return retArr; + } + + public static float parseFloat(String val) + { + /* + if (val == null) return 0f; + + float retVal = 0f; + try + { retVal = Float.parseFloat(val); } + catch (Exception e) + {} + return retVal; + */ + return findFloat(val); + } + + /** + * Searches the given string for the first floating point number it contains, + * parses and returns it. + */ + public synchronized static float findFloat(String val) + { + if (val == null) return 0f; + + fpMatch.reset(val); + if (!fpMatch.find()) return 0f; + + val = fpMatch.group(1); + //System.err.println("Parsing " + val); + + float retVal = 0f; + try + { + retVal = Float.parseFloat(val); + String units = fpMatch.group(6); + if ("%".equals(units)) retVal /= 100; + } + catch (Exception e) + {} + return retVal; + } + + public synchronized static float[] parseFloatList(String list) + { + if (list == null) return null; + + fpMatch.reset(list); + + LinkedList floatList = new LinkedList(); + while (fpMatch.find()) + { + String val = fpMatch.group(1); + floatList.add(Float.valueOf(val)); + } + + float[] retArr = new float[floatList.size()]; + Iterator it = floatList.iterator(); + int idx = 0; + while (it.hasNext()) + { + retArr[idx++] = ((Float)it.next()).floatValue(); + } + + return retArr; + } + + public static int parseInt(String val) + { + if (val == null) return 0; + + int retVal = 0; + try + { retVal = Integer.parseInt(val); } + catch (Exception e) + {} + return retVal; + } + + /** + * Searches the given string for the first integer point number it contains, + * parses and returns it. + */ + public static int findInt(String val) + { + if (val == null) return 0; + + intMatch.reset(val); + if (!intMatch.find()) return 0; + + val = intMatch.group(); + //System.err.println("Parsing " + val); + + int retVal = 0; + try + { retVal = Integer.parseInt(val); } + catch (Exception e) + {} + return retVal; + } + + public static int[] parseIntList(String list) + { + if (list == null) return null; + + intMatch.reset(list); + + LinkedList intList = new LinkedList(); + while (intMatch.find()) + { + String val = intMatch.group(); + intList.add(Integer.valueOf(val)); + } + + int[] retArr = new int[intList.size()]; + Iterator it = intList.iterator(); + int idx = 0; + while (it.hasNext()) + { + retArr[idx++] = ((Integer)it.next()).intValue(); + } + + return retArr; + } +/* + 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; + } +*/ + /** + * The input string represents a ratio. Can either be specified as a + * double number on the range of [0.0 1.0] or as a percentage [0% 100%] + */ + public static double parseRatio(String val) + { + if (val == null || val.equals("")) return 0.0; + + if (val.charAt(val.length() - 1) == '%') + { + parseDouble(val.substring(0, val.length() - 1)); + } + return parseDouble(val); + } + + public static NumberWithUnits parseNumberWithUnits(String val) + { + if (val == null) return null; + + return new NumberWithUnits(val); + } +/* + public static Color parseColor(String val) + { + Color retVal = 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 Matcher rgbMatch = Pattern.compile("rgb\\((\\d+),(\\d+),(\\d+)\\)", Pattern.CASE_INSENSITIVE).matcher(""); + + rgbMatch.reset(val); + if (rgbMatch.matches()) + { + int r = Integer.parseInt(rgbMatch.group(1)); + int g = Integer.parseInt(rgbMatch.group(2)); + int b = Integer.parseInt(rgbMatch.group(3)); + retVal = new Color(r, g, b); + } + else + { + Color lookupCol = ColorTable.instance().lookupColor(val); + if (lookupCol != null) retVal = lookupCol; + } + } + + return retVal; + } +*/ + /** + * Parses the given attribute of this tag and returns it as a String. + */ + public static String getAttribString(Element ele, String name) + { + return ele.getAttribute(name); + } + + /** + * Parses the given attribute of this tag and returns it as an int. + */ + public static int getAttribInt(Element ele, String name) + { + String sval = ele.getAttribute(name); + int val = 0; + try { val = Integer.parseInt(sval); } catch (Exception e) {} + + return val; + } + + /** + * Parses the given attribute of this tag as a hexadecimal encoded string and + * returns it as an int + */ + public static int getAttribIntHex(Element ele, String name) + { + String sval = ele.getAttribute(name); + int val = 0; + try { val = Integer.parseInt(sval, 16); } catch (Exception e) {} + + return val; + } + + /** + * Parses the given attribute of this tag and returns it as a float + */ + public static float getAttribFloat(Element ele, String name) + { + String sval = ele.getAttribute(name); + float val = 0.0f; + try { val = Float.parseFloat(sval); } catch (Exception e) {} + + return val; + } + + /** + * Parses the given attribute of this tag and returns it as a double. + */ + public static double getAttribDouble(Element ele, String name) + { + String sval = ele.getAttribute(name); + double val = 0.0; + try { val = Double.parseDouble(sval); } catch (Exception e) {} + + return val; + } + + /** + * Parses the given attribute of this tag and returns it as a boolean. + * Essentially compares the lower case textual value to the string "true" + */ + public static boolean getAttribBoolean(Element ele, String name) + { + String sval = ele.getAttribute(name); + + return sval.toLowerCase().equals("true"); + } + + public static URL getAttribURL(Element ele, String name, URL docRoot) + { + String sval = ele.getAttribute(name); + + try + { + return new URL(docRoot, sval); + } + catch (Exception e) + { + return null; + } + } + + /** + * Returns the first ReadableXMLElement with the given name + */ + public static ReadableXMLElement getElement(Class classType, Element root, String name, URL docRoot) + { + if (root == null) return null; + + //Do not process if not a LoadableObject + if (!ReadableXMLElement.class.isAssignableFrom(classType)) + { + return null; + } + + NodeList nl = root.getChildNodes(); + int size = nl.getLength(); + for (int i = 0; i < size; i++) + { + Node node = nl.item(i); + if (!(node instanceof Element)) continue; + Element ele = (Element)node; + if (!ele.getTagName().equals(name)) continue; + + ReadableXMLElement newObj = null; + try + { + newObj = (ReadableXMLElement)classType.newInstance(); + } + catch (Exception e) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); + continue; + } + newObj.read(ele, docRoot); + + if (newObj == null) continue; + + return newObj; + } + + return null; + } + + /** + * Returns a HashMap of nodes that are children of root. All nodes will + * be of class classType and have a tag name of 'name'. 'key' is + * an attribute of tag 'name' who's string value will be used as the key + * in the HashMap + */ + public static HashMap getElementHashMap(Class classType, Element root, String name, String key, URL docRoot) + { + if (root == null) return null; + + //Do not process if not a LoadableObject + if (!ReadableXMLElement.class.isAssignableFrom(classType)) + { + return null; + } + + HashMap retMap = new HashMap(); + + NodeList nl = root.getChildNodes(); + int size = nl.getLength(); + for (int i = 0; i < size; i++) + { + Node node = nl.item(i); + if (!(node instanceof Element)) continue; + Element ele = (Element)node; + if (!ele.getTagName().equals(name)) continue; + + ReadableXMLElement newObj = null; + try + { + newObj = (ReadableXMLElement)classType.newInstance(); + } + catch (Exception e) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); + continue; + } + newObj.read(ele, docRoot); + + if (newObj == null) continue; + + String keyVal = getAttribString(ele, key); + retMap.put(keyVal, newObj); + } + + return retMap; + } + + public static HashSet getElementHashSet(Class classType, Element root, String name, URL docRoot) + { + if (root == null) return null; + + //Do not process if not a LoadableObject + if (!ReadableXMLElement.class.isAssignableFrom(classType)) + { + return null; + } + + HashSet retSet = new HashSet(); + + NodeList nl = root.getChildNodes(); + int size = nl.getLength(); + for (int i = 0; i < size; i++) + { + Node node = nl.item(i); + if (!(node instanceof Element)) continue; + Element ele = (Element)node; + if (!ele.getTagName().equals(name)) continue; + + ReadableXMLElement newObj = null; + try + { + newObj = (ReadableXMLElement)classType.newInstance(); + } + catch (Exception e) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); + continue; + } + newObj.read(ele, docRoot); + + if (newObj == null) + { + continue; + } + + retSet.add(newObj); + } + + return retSet; + } + + + public static LinkedList getElementLinkedList(Class classType, Element root, String name, URL docRoot) + { + if (root == null) return null; + + //Do not process if not a LoadableObject + if (!ReadableXMLElement.class.isAssignableFrom(classType)) + { + return null; + } + + NodeList nl = root.getChildNodes(); + LinkedList elementCache = new LinkedList(); + int size = nl.getLength(); + for (int i = 0; i < size; i++) + { + Node node = nl.item(i); + if (!(node instanceof Element)) continue; + Element ele = (Element)node; + if (!ele.getTagName().equals(name)) continue; + + ReadableXMLElement newObj = null; + try + { + newObj = (ReadableXMLElement)classType.newInstance(); + } + catch (Exception e) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); + continue; + } + newObj.read(ele, docRoot); + + elementCache.addLast(newObj); + } + + return elementCache; + } + + public static Object[] getElementArray(Class classType, Element root, String name, URL docRoot) + { + if (root == null) return null; + + //Do not process if not a LoadableObject + if (!ReadableXMLElement.class.isAssignableFrom(classType)) + { + return null; + } + + LinkedList elementCache = getElementLinkedList(classType, root, name, docRoot); + + Object[] retArr = (Object[])Array.newInstance(classType, elementCache.size()); + return elementCache.toArray(retArr); + } + + /** + * Takes a number of tags of name 'name' that are children of 'root', and + * looks for attributes of 'attrib' on them. Converts attributes to an + * int and returns in an array. + */ + public static int[] getElementArrayInt(Element root, String name, String attrib) + { + if (root == null) return null; + + NodeList nl = root.getChildNodes(); + LinkedList elementCache = new LinkedList(); + int size = nl.getLength(); + + for (int i = 0; i < size; i++) + { + Node node = nl.item(i); + if (!(node instanceof Element)) continue; + Element ele = (Element)node; + if (!ele.getTagName().equals(name)) continue; + + String valS = ele.getAttribute(attrib); + int eleVal = 0; + try { eleVal = Integer.parseInt(valS); } + catch (Exception e) {} + + elementCache.addLast(new Integer(eleVal)); + } + + int[] retArr = new int[elementCache.size()]; + Iterator it = elementCache.iterator(); + int idx = 0; + while (it.hasNext()) + { + retArr[idx++] = it.next().intValue(); + } + + return retArr; + } + + /** + * Takes a number of tags of name 'name' that are children of 'root', and + * looks for attributes of 'attrib' on them. Converts attributes to an + * int and returns in an array. + */ + public static String[] getElementArrayString(Element root, String name, String attrib) + { + if (root == null) return null; + + NodeList nl = root.getChildNodes(); + LinkedList elementCache = new LinkedList(); + int size = nl.getLength(); + + for (int i = 0; i < size; i++) + { + Node node = nl.item(i); + if (!(node instanceof Element)) continue; + Element ele = (Element)node; + if (!ele.getTagName().equals(name)) continue; + + String valS = ele.getAttribute(attrib); + + elementCache.addLast(valS); + } + + String[] retArr = new String[elementCache.size()]; + Iterator it = elementCache.iterator(); + int idx = 0; + while (it.hasNext()) + { + retArr[idx++] = it.next(); + } + + return retArr; + } + + /** + * Takes a CSS style string and retursn a hash of them. + * @param styleString - A CSS formatted string of styles. Eg, + * "font-size:12;fill:#d32c27;fill-rule:evenodd;stroke-width:1pt;" + */ + public static HashMap parseStyle(String styleString) { + return parseStyle(styleString, new HashMap()); + } + + /** + * Takes a CSS style string and returns a hash of them. + * @param styleString - A CSS formatted string of styles. Eg, + * "font-size:12;fill:#d32c27;fill-rule:evenodd;stroke-width:1pt;" + * @param map - A map to which these styles will be added + */ + public static HashMap parseStyle(String styleString, HashMap map) { + final Pattern patSemi = Pattern.compile(";"); + + String[] styles = patSemi.split(styleString); + + for (int i = 0; i < styles.length; i++) + { + if (styles[i].length() == 0) + { + continue; + } + + int colon = styles[i].indexOf(':'); + if (colon == -1) + { + continue; + } + + String key = styles[i].substring(0, colon).trim().intern(); + String value = quoteMatch.reset(styles[i].substring(colon + 1).trim()).replaceAll("").intern(); + + map.put(key, new StyleAttribute(key, value)); + } + + return map; + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/cpx/CPXConsts.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/cpx/CPXConsts.java new file mode 100644 index 0000000..37a565d --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/cpx/CPXConsts.java @@ -0,0 +1,49 @@ +/* + * 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 12, 2004, 12:51 PM + */ + +package org.xbib.graphics.svg.xml.cpx; + +/** + * @author Mark McKay + * @author Mark McKay + */ +public interface CPXConsts { + + static final byte[] MAGIC_NUMBER = {'C', 'P', 'X', 0}; + + static final int XL_PLAIN = 0; + static final int XL_ZIP_CRYPT = 1; +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/cpx/CPXInputStream.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/cpx/CPXInputStream.java new file mode 100644 index 0000000..9874990 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/cpx/CPXInputStream.java @@ -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 February 12, 2004, 10:34 AM + */ + +package org.xbib.graphics.svg.xml.cpx; + +import org.xbib.graphics.svg.SVGConst; +import java.io.*; +import java.util.zip.*; +import java.security.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class reads/decodes the CPX file format. This format is a simple + * compression/encryption transformer for XML data. This stream takes in + * encrypted XML and outputs decrypted. It does this by checking for a magic + * number at the start of the stream. If absent, it treats the stream as + * raw XML data and passes it through unaltered. This is to aid development + * in debugging versions, where the XML files will not be in CPX format. + * + * See http://java.sun.com/developer/technicalArticles/Security/Crypto/ + * + * @author Mark McKay + * @author Mark McKay + */ +public class CPXInputStream extends FilterInputStream implements CPXConsts { + + + SecureRandom sec = new SecureRandom(); + + Inflater inflater = new Inflater(); + + int xlateMode; + + //Keep header bytes in case this stream turns out to be plain text + byte[] head = new byte[4]; + int headSize = 0; + int headPtr = 0; + + boolean reachedEOF = false; + byte[] inBuffer = new byte[2048]; + byte[] decryptBuffer = new byte[2048]; + + /** + * Creates a new instance of CPXInputStream + * @param in + * @throws java.io.IOException + */ + public CPXInputStream(InputStream in) throws IOException { + super(in); + + //Determine processing type + for (int i = 0; i < 4; i++) + { + int val = in.read(); + head[i] = (byte)val; + if (val == -1 || head[i] != MAGIC_NUMBER[i]) + { + headSize = i + 1; + xlateMode = XL_PLAIN; + return; + } + } + + xlateMode = XL_ZIP_CRYPT; + } + + /** + * We do not allow marking + */ + @Override + public boolean markSupported() { return false; } + + /** + * Closes this input stream and releases any system resources + * associated with the stream. + * This + * method simply performs in.close(). + * + * @exception IOException if an I/O error occurs. + * @see java.io.FilterInputStream#in + */ + @Override + public void close() throws IOException { + reachedEOF = true; + in.close(); + } + + /** + * Reads the next byte of data from this input stream. The value + * byte is returned as an int in the range + * 0 to 255. If no byte is available + * because the end of the stream has been reached, the value + * -1 is returned. This method blocks until input data + * is available, the end of the stream is detected, or an exception + * is thrown. + *

+ * This method + * simply performs in.read() and returns the result. + * + * @return the next byte of data, or -1 if the end of the + * stream is reached. + * @exception IOException if an I/O error occurs. + * @see java.io.FilterInputStream#in + */ + @Override + public int read() throws IOException + { + final byte[] b = new byte[1]; + int retVal = read(b, 0, 1); + if (retVal == -1) return -1; + return b[0]; + } + + /** + * Reads up to byte.length bytes of data from this + * input stream into an array of bytes. This method blocks until some + * input is available. + *

+ * This method simply performs the call + * read(b, 0, b.length) and returns + * the result. It is important that it does + * not do in.read(b) instead; + * certain subclasses of FilterInputStream + * depend on the implementation strategy actually + * used. + * + * @param b the buffer into which the data is read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the stream has been reached. + * @exception IOException if an I/O error occurs. + * @see java.io.FilterInputStream#read(byte[], int, int) + */ + @Override + public int read(byte[] b) throws IOException + { + return read(b, 0, b.length); + } + + /** + * Reads up to len bytes of data from this input stream + * into an array of bytes. This method blocks until some input is + * available. + *

+ * This method simply performs in.read(b, off, len) + * and returns the result. + * + * @param b the buffer into which the data is read. + * @param off the start offset of the data. + * @param len the maximum number of bytes read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the stream has been reached. + * @exception IOException if an I/O error occurs. + * @see java.io.FilterInputStream#in + */ + @Override + public int read(byte[] b, int off, int len) throws IOException + { + if (reachedEOF) return -1; + + if (xlateMode == XL_PLAIN) + { + int count = 0; + //Write header if appropriate + while (headPtr < headSize && len > 0) + { + b[off++] = head[headPtr++]; + count++; + len--; + } + + return (len == 0) ? count : count + in.read(b, off, len); + } + + //Decrypt and inflate + if (inflater.needsInput() && !decryptChunk()) + { + reachedEOF = true; + + //Read remaining bytes + int numRead; + try { + numRead = inflater.inflate(b, off, len); + } + catch (Exception e) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); + return -1; + } + + if (!inflater.finished()) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, + "Inflation imncomplete"); + } + + return numRead == 0 ? -1 : numRead; + } + + try + { + return inflater.inflate(b, off, len); + } + catch (DataFormatException e) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); + return -1; + } + } + + + /** + * Call when inflater indicates that it needs more bytes. + * @return - true if we decrypted more bytes to deflate, false if we + * encountered the end of stream + * @throws java.io.IOException + */ + protected boolean decryptChunk() throws IOException + { + while (inflater.needsInput()) + { + int numInBytes = in.read(inBuffer); + if (numInBytes == -1) return false; +// int numDecryptBytes = cipher.update(inBuffer, 0, numInBytes, decryptBuffer); +// inflater.setInput(decryptBuffer, 0, numDecryptBytes); +inflater.setInput(inBuffer, 0, numInBytes); + } + + return true; + } + + /** + * This method returns 1 if we've not reached EOF, 0 if we have. Programs + * should not rely on this to determine the number of bytes that can be + * read without blocking. + */ + @Override + public int available() { return reachedEOF ? 0 : 1; } + + /** + * Skips bytes by reading them into a cached buffer + */ + @Override + public long skip(long n) throws IOException + { + int skipSize = (int)n; + if (skipSize > inBuffer.length) skipSize = inBuffer.length; + return read(inBuffer, 0, skipSize); + } + +} + +/* + import java.security.KeyPairGenerator; + import java.security.KeyPair; + import java.security.KeyPairGenerator; + import java.security.PrivateKey; + import java.security.PublicKey; + import java.security.SecureRandom; + import java.security.Cipher; + + .... + + java.security.Security.addProvider(new cryptix.provider.Cryptix()); + + SecureRandom random = new SecureRandom(SecureRandom.getSeed(30)); + KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA"); + keygen.initialize(1024, random); + keypair = keygen.generateKeyPair(); + + PublicKey pubkey = keypair.getPublic(); + PrivateKey privkey = keypair.getPrivate(); + */ + +/* + * + *Generate key pairs +KeyPairGenerator keyGen = + KeyPairGenerator.getInstance("DSA"); +KeyGen.initialize(1024, new SecureRandom(userSeed)); +KeyPair pair = KeyGen.generateKeyPair(); + */ \ No newline at end of file diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/cpx/CPXOutputStream.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/cpx/CPXOutputStream.java new file mode 100644 index 0000000..0e55f54 --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/cpx/CPXOutputStream.java @@ -0,0 +1,190 @@ +/* + * 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 12, 2004, 12:50 PM + */ + +package org.xbib.graphics.svg.xml.cpx; + +import java.io.*; +import java.util.zip.*; + +/** + * @author Mark McKay + * @author Mark McKay + */ +public class CPXOutputStream extends FilterOutputStream implements CPXConsts { + + Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION); + + /** + * Creates a new instance of CPXOutputStream + * @param os + * @throws java.io.IOException + */ + public CPXOutputStream(OutputStream os) throws IOException { + super(os); + + //Write magic number + os.write(MAGIC_NUMBER); + } + + /** + * Writes the specified byte to this output stream. + *

+ * The write method of FilterOutputStream + * calls the write method of its underlying output stream, + * that is, it performs out.write(b). + *

+ * Implements the abstract write method of OutputStream. + * + * @param b the byte. + * @exception IOException if an I/O error occurs. + */ + @Override + public void write(int b) throws IOException { + final byte[] buf = new byte[1]; + buf[0] = (byte)b; + write(buf, 0, 1); + } + + /** + * Writes b.length bytes to this output stream. + *

+ * The write method of FilterOutputStream + * calls its write method of three arguments with the + * arguments b, 0, and + * b.length. + *

+ * Note that this method does not call the one-argument + * write method of its underlying stream with the single + * argument b. + * + * @param b the data to be written. + * @exception IOException if an I/O error occurs. + * @see java.io.FilterOutputStream#write(byte[], int, int) + */ + @Override + public void write(byte b[]) throws IOException { + write(b, 0, b.length); + } + + byte[] deflateBuffer = new byte[2048]; + + /** + * Writes len bytes from the specified + * byte array starting at offset off to + * this output stream. + *

+ * The write method of FilterOutputStream + * calls the write method of one argument on each + * byte to output. + *

+ * Note that this method does not call the write method + * of its underlying input stream with the same arguments. Subclasses + * of FilterOutputStream should provide a more efficient + * implementation of this method. + * + * @param b the data. + * @param off the start offset in the data. + * @param len the number of bytes to write. + * @exception IOException if an I/O error occurs. + * @see java.io.FilterOutputStream#write(int) + */ + @Override + public void write(byte b[], int off, int len) throws IOException + { + deflater.setInput(b, off, len); + + processAllData(); + /* + int numDeflatedBytes; + while ((numDeflatedBytes = deflater.deflate(deflateBuffer)) != 0) + { +// byte[] cipherBuf = cipher.update(deflateBuffer, 0, numDeflatedBytes); +// out.write(cipherBytes); +out.write(deflateBuffer, 0, numDeflatedBytes); + } + */ + } + + protected void processAllData() throws IOException + { + int numDeflatedBytes; + while ((numDeflatedBytes = deflater.deflate(deflateBuffer)) != 0) + { +// byte[] cipherBuf = cipher.update(deflateBuffer, 0, numDeflatedBytes); +// out.write(cipherBytes); +out.write(deflateBuffer, 0, numDeflatedBytes); + } + } + + /** + * Flushes this output stream and forces any buffered output bytes + * to be written out to the stream. + *

+ * The flush method of FilterOutputStream + * calls the flush method of its underlying output stream. + * + * @exception IOException if an I/O error occurs. + * @see java.io.FilterOutputStream#out + */ + @Override + public void flush() throws IOException { + out.flush(); + } + + /** + * Closes this output stream and releases any system resources + * associated with the stream. + *

+ * The close method of FilterOutputStream + * calls its flush method, and then calls the + * close method of its underlying output stream. + * + * @exception IOException if an I/O error occurs. + * @see java.io.FilterOutputStream#flush() + * @see java.io.FilterOutputStream#out + */ + @Override + public void close() throws IOException { + deflater.finish(); + processAllData(); + + try { + flush(); + } catch (IOException ignored) { + } + out.close(); + } +} diff --git a/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/cpx/CPXTest.java b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/cpx/CPXTest.java new file mode 100644 index 0000000..6d9015c --- /dev/null +++ b/graphics-svg/src/main/java/org/xbib/graphics/svg/xml/cpx/CPXTest.java @@ -0,0 +1,112 @@ +/* + * 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 12, 2004, 2:45 PM + */ + +package org.xbib.graphics.svg.xml.cpx; + +import org.xbib.graphics.svg.SVGConst; +import java.io.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * @author Mark McKay + * @author Mark McKay + */ +public class CPXTest { + + /** Creates a new instance of CPXTest */ + public CPXTest() { + +// FileInputStream fin = new FileInputStream(); + writeTest(); + readTest(); + } + + public void writeTest() + { + try { + + InputStream is = CPXTest.class.getResourceAsStream("/data/readme.txt"); +//System.err.println("Is " + is); + + FileOutputStream fout = new FileOutputStream("C:\\tmp\\cpxFile.cpx"); + CPXOutputStream cout = new CPXOutputStream(fout); + + byte[] buffer = new byte[1024]; + int numBytes; + while ((numBytes = is.read(buffer)) != -1) + { + cout.write(buffer, 0, numBytes); + } + cout.close(); + } + catch (Exception e) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); + } + } + + public void readTest() + { + try { + +// InputStream is = CPXTest.class.getResourceAsStream("/rawdata/test/cpx/text.txt"); +// InputStream is = CPXTest.class.getResourceAsStream("/rawdata/test/cpx/cpxFile.cpx"); + FileInputStream is = new FileInputStream("C:\\tmp\\cpxFile.cpx"); + CPXInputStream cin = new CPXInputStream(is); + + BufferedReader br = new BufferedReader(new InputStreamReader(cin)); + String line; + while ((line = br.readLine()) != null) + { + System.err.println(line); + } + } + catch (Exception e) + { + Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); + } + } + + /** + * @param args the command line arguments + */ + public static void main(String[] args) + { + new CPXTest(); + } + +} diff --git a/graphics-svg/src/test/res/1C2EC147.png b/graphics-svg/src/test/res/1C2EC147.png new file mode 100644 index 0000000..e33dd29 Binary files /dev/null and b/graphics-svg/src/test/res/1C2EC147.png differ diff --git a/graphics-svg/src/test/res/1C2EC148.png b/graphics-svg/src/test/res/1C2EC148.png new file mode 100644 index 0000000..e33dd29 Binary files /dev/null and b/graphics-svg/src/test/res/1C2EC148.png differ diff --git a/graphics-svg/src/test/res/AdamTagletClasses.svg b/graphics-svg/src/test/res/AdamTagletClasses.svg new file mode 100644 index 0000000..ac5b85f --- /dev/null +++ b/graphics-svg/src/test/res/AdamTagletClasses.svg @@ -0,0 +1,104 @@ + + +]> + + + + +DigraphName + + +net_walend_adamtaglet_AdamTaglet + + +AdamTaglet + + + +com_sun_tools_doclets_internal_toolkit_taglets_Taglet + + +com.sun.tools.doclets.internal.toolkit.taglets.Taglet + + + +com_sun_tools_doclets_internal_toolkit_taglets_Taglet->net_walend_adamtaglet_AdamTaglet + + + + +net_walend_adamtaglet_ClassDiagramBuilder + + +ClassDiagramBuilder + + + +net_walend_adamtaglet_ClassDiagramVisitor + + +ClassDiagramVisitor + + + +net_walend_tographviz_ToGraphvizVisitor + + +net.walend.tographviz.ToGraphvizVisitor + + + +net_walend_tographviz_ToGraphvizVisitor->net_walend_adamtaglet_ClassDiagramVisitor + + + + +net_walend_adamtaglet_Relationship + + +Relationship + + + +java_lang_Enum + + +java.lang.Enum + + + +java_lang_Enum->net_walend_adamtaglet_Relationship + + + + +java_lang_Comparable + + +java.lang.Comparable + + + +java_lang_Comparable->java_lang_Enum + + + + +java_io_Serializable + + +java.io.Serializable + + + +java_io_Serializable->java_lang_Enum + + + + + diff --git a/graphics-svg/src/test/res/Monitor.svg b/graphics-svg/src/test/res/Monitor.svg new file mode 100644 index 0000000..9e07a3f --- /dev/null +++ b/graphics-svg/src/test/res/Monitor.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/graphics-svg/src/test/res/bad_alias.svg b/graphics-svg/src/test/res/bad_alias.svg new file mode 100644 index 0000000..4adc92d --- /dev/null +++ b/graphics-svg/src/test/res/bad_alias.svg @@ -0,0 +1,131 @@ + + + + +]> + + + + + + + diff --git a/graphics-svg/src/test/res/bad_alias2.svg b/graphics-svg/src/test/res/bad_alias2.svg new file mode 100644 index 0000000..81fc016 --- /dev/null +++ b/graphics-svg/src/test/res/bad_alias2.svg @@ -0,0 +1,229 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/graphics-svg/src/test/res/bad_alias3.svg b/graphics-svg/src/test/res/bad_alias3.svg new file mode 100644 index 0000000..a74e8bd --- /dev/null +++ b/graphics-svg/src/test/res/bad_alias3.svg @@ -0,0 +1,5689 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COMPRESSOR 1 CYLINDER + 8501031 + E + W + I + T + H + O + U + T + + O + I + L + + E + Q + U + A + L + I + S + A + T + I + O + N + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 25 + + .98 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 98 + + 3.85 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 68 + + 2.67 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 109 + + 4.29 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15 + + .60 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 23 + + .90 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 17 + + .67 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 39 + + 1.52 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 118 + + 4.65 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 123 + + 4.84 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 68 + + 2.68 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 35° + + + + + + + + + + + + + + + + 263 + + 10.34 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 82 + + 3.22 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SUCTION + + D + + I + + S + + C + + H + + A + + R + + G + + E + + + + 142 + + 5.59 + + [ + + ] + + 142 + + 5.60 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ø + + 224 + + 8.83 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 333 + + 13.12 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ø + + 31,75 + + 1.25 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 159 + + 6.26 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + C + + O + + M + + P + + R + + E + + S + + S + + O + + R + + S + + MT/MTZ 18-3/4 + + MT/MTZ 22-3/4/6 + + MT/MTZ 28-3/4/6 + + + + S + U + + C + + T + + I + + O + + N + + + + R + + O + + T + + A + + L + + O + + C + + K + + 1" + + + + D + + I + + S + + C + + H + + A + + R + + G + + E + + + + R + + O + + T + + A + + L + + O + + C + + K + + 1" + + + + P + + T + + C + + + + C + + R + + A + + N + + K + + C + + A + + S + + E + + + + H + + E + + A + + T + + E + + R + + + + S + + C + + H + + R + + A + + D + + E + + R + + 1/4" + + + + B + + O + + L + + T + + + + H + + + + M + + 8 + + - + + 4 + + 0 + + G + + R + + O + + M + + M + + E + + T + + + + C + + O + + M + + P + + R + + E + + S + + S + + I + + O + + N + + + + N + + O + + T + + + + I + + N + + C + + L + + U + + D + + E + + D + + , + + A + + R + + O + + U + + N + + D + + + + 1 + + + + M + + M + + S + + I + + L + + E + + N + + T + + B + + L + + O + + C + + K + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/graphics-svg/src/test/res/data-uri-scheme-test-image.svg b/graphics-svg/src/test/res/data-uri-scheme-test-image.svg new file mode 100644 index 0000000..a6356be --- /dev/null +++ b/graphics-svg/src/test/res/data-uri-scheme-test-image.svg @@ -0,0 +1,23 @@ + + + + +]> + + + + + + + + + + + + + + + + diff --git a/graphics-svg/src/test/res/drawing.svg b/graphics-svg/src/test/res/drawing.svg new file mode 100644 index 0000000..77a6dc1 --- /dev/null +++ b/graphics-svg/src/test/res/drawing.svg @@ -0,0 +1,9361 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A + P + P + R + O + B + A + T + I + O + N + M + A + T + I + E + R + E + : + P + A + R + D + A + T + E + T + o + l + . + g + e + n + : + E + c + h + : + IND + M + O + D + I + F + I + C + A + T + I + O + N + S + + C + e + + p + l + a + n + + e + s + t + + l + a + + p + r + o + p + r + i + e + t + e + + d + e + + D + a + n + f + o + s + s + + C + o + m + m + e + r + c + i + a + l + + C + o + m + p + r + e + s + s + o + r + s + , + + t + o + u + t + e + + c + o + p + i + e + + o + u + + c + o + m + m + u + n + i + c + a + t + i + o + n + + a + + d + e + s + + t + i + e + r + s + e + s + t + + i + n + t + e + r + d + i + t + e + + s + a + n + s + + a + u + t + o + r + i + s + a + t + i + o + n + . + + T + h + i + s + + d + r + a + w + i + n + g + + i + s + + p + r + o + p + r + i + e + t + a + r + y + + a + n + d + + s + h + a + l + l + + n + o + t + + b + e + + c + o + p + i + e + d + + o + r + + i + t + s + c + o + n + t + e + n + t + s + + d + i + s + c + l + o + s + e + d + + t + o + + o + u + t + s + i + d + e + + p + a + r + t + i + e + s + + w + i + t + h + o + u + t + + t + h + e + + w + r + i + t + t + e + n + + c + o + n + s + e + n + t + + o + f + + D + a + n + f + o + s + s + + C + o + m + m + e + r + c + i + a + l + + C + o + m + p + r + e + s + s + o + r + s + 3D + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 518 + + 20.40 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 99 + 3.91 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 95 + 3.75 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 125 + 4.92 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 233 + 9.18 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 246 + 9.70 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 246 + 9.70 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 210 + 8.28 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 209 + 8.24 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 205 + 8.07 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 155 + 6.10 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 117 + 4.61 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ø + + 352 + + 13.85 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 98 + 3.84 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 232 + 9.12 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15° + + + + + + + + + + + + + + + 15° + + + + + + + + + + + + + + + 15° + + + + + + + + + + + + + + + 19 + .75 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30 + 1.19 + [ + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8504010 + + + + + + + + + A1 + + + + + + + + + 1/2 + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D + a + n + f + o + s + s + + C + o + m + m + e + r + c + i + a + l + C + o + m + p + r + e + s + s + o + r + s + B + . + P + . + 3 + 3 + 1 + F + - + 0 + 1 + 6 + 0 + 3 + + T + r + e + v + o + u + x + + F + r + a + n + c + e + T + e + l + . + + : + F + a + x + : + + + 3 + 3 + + ( + 0 + ) + + 4 + + 7 + 4 + + 0 + 0 + + 2 + 8 + + 2 + 9 + + + 3 + 3 + + ( + 0 + ) + + 4 + + 7 + 4 + + 0 + 0 + + 5 + 2 + + 4 + 4 + + + + + + + + + + + + + + + + + + + 4 + + C + Y + L + I + N + D + R + E + S + + / + + V + E + + / + + B + A + S + S + E + + + + + + + + + 4 + + C + y + l + i + n + d + e + r + s + + / + + V + E + + / + + L + o + w + + + + + + + + + + + + + + + + + + + + + + + + + + + E + ADA + 23/06/05 + J + B + V + + DC 1020861 / 1050271 / 1050272 + + + + + + + + + + C + O + M + P + R + E + S + S + O + R + S + + M + T + / + M + T + Z + + 1 + 0 + 0 + - + 3 + / + 4 + / + 6 + / + 7 + / + 9 + M + T + / + M + T + Z + + 1 + 2 + 5 + - + 3 + / + 4 + / + 6 + / + 7 + / + 9 + L + T + Z + + 8 + 8 + - + 3 + / + 4 + / + 6 + / + 7 + / + 9 + L + T + Z + + 1 + 0 + 0 + - + 3 + / + 4 + / + 6 + / + 7 + / + 9 + N + T + Z + + 2 + 7 + 1 + - + 3 + / + 4 + N + T + Z + + 2 + 1 + 5 + - + 3 + / + 4 + V + T + Z + + 1 + 7 + 1 + - + G + / + H + V + T + Z + + 2 + 1 + 5 + - + G + / + H + + O + I + L + + E + Q + U + A + L + I + S + A + T + I + O + N + 3 + / + 8 + " + + + + + + + + T + H + R + E + A + D + E + D + + O + I + L + S + I + G + H + T + + G + L + A + S + S + + + + + + + + S + C + H + R + A + D + E + R + 1 + / + 4 + " + + + + + + + + S + U + C + T + I + O + N + + R + O + T + A + L + O + C + K + 1 + " + 3 + / + 4 + + + + + + + + D + I + S + C + H + A + R + G + E + + R + O + T + A + L + O + C + K + 1 + " + 1 + / + 4 + + + + + + + + P + T + C + C + R + A + N + K + C + A + S + E + + H + E + A + T + E + R + + + + + + + B + O + L + T + + H + + M + 1 + 2 + - + 5 + 0 + + + + + + + + G + R + O + M + M + E + T + + C + O + M + P + R + E + S + S + I + O + N + + N + O + T + + I + N + C + L + U + D + E + D + A + R + O + U + N + D + + 1 + + M + M + S + I + L + E + N + T + + B + L + O + C + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/graphics-svg/src/test/res/embed_image.svg b/graphics-svg/src/test/res/embed_image.svg new file mode 100644 index 0000000..92bc10a --- /dev/null +++ b/graphics-svg/src/test/res/embed_image.svg @@ -0,0 +1,5689 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COMPRESSOR 1 CYLINDER + 8501031 + E + W + I + T + H + O + U + T + + O + I + L + + E + Q + U + A + L + I + S + A + T + I + O + N + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 25 + + .98 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 98 + + 3.85 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 68 + + 2.67 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 109 + + 4.29 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15 + + .60 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 23 + + .90 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 17 + + .67 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 39 + + 1.52 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 118 + + 4.65 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 123 + + 4.84 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 68 + + 2.68 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 35° + + + + + + + + + + + + + + + + 263 + + 10.34 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 82 + + 3.22 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SUCTION + + D + + I + + S + + C + + H + + A + + R + + G + + E + + + + 142 + + 5.59 + + [ + + ] + + 142 + + 5.60 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ø + + 224 + + 8.83 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 333 + + 13.12 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ø + + 31,75 + + 1.25 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 159 + + 6.26 + + [ + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + C + + O + + M + + P + + R + + E + + S + + S + + O + + R + + S + + MT/MTZ 18-3/4 + + MT/MTZ 22-3/4/6 + + MT/MTZ 28-3/4/6 + + + + S + U + + C + + T + + I + + O + + N + + + + R + + O + + T + + A + + L + + O + + C + + K + + 1" + + + + D + + I + + S + + C + + H + + A + + R + + G + + E + + + + R + + O + + T + + A + + L + + O + + C + + K + + 1" + + + + P + + T + + C + + + + C + + R + + A + + N + + K + + C + + A + + S + + E + + + + H + + E + + A + + T + + E + + R + + + + S + + C + + H + + R + + A + + D + + E + + R + + 1/4" + + + + B + + O + + L + + T + + + + H + + + + M + + 8 + + - + + 4 + + 0 + + G + + R + + O + + M + + M + + E + + T + + + + C + + O + + M + + P + + R + + E + + S + + S + + I + + O + + N + + + + N + + O + + T + + + + I + + N + + C + + L + + U + + D + + E + + D + + , + + A + + R + + O + + U + + N + + D + + + + 1 + + + + M + + M + + S + + I + + L + + E + + N + + T + + B + + L + + O + + C + + K + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/graphics-svg/src/test/res/embed_image.svgz b/graphics-svg/src/test/res/embed_image.svgz new file mode 100644 index 0000000..fe74789 Binary files /dev/null and b/graphics-svg/src/test/res/embed_image.svgz differ diff --git a/graphics-svg/src/test/res/missing.svg b/graphics-svg/src/test/res/missing.svg new file mode 100644 index 0000000..d540986 --- /dev/null +++ b/graphics-svg/src/test/res/missing.svg @@ -0,0 +1,1090 @@ + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12 + + + + 14 + + + + 11 + + + + N + + + + 2 + + + + 1 + + + + L1 + + + + + + + + + + + + + + + + + + + diff --git a/graphics-svg/src/test/res/missing.svgz b/graphics-svg/src/test/res/missing.svgz new file mode 100644 index 0000000..051d5e7 Binary files /dev/null and b/graphics-svg/src/test/res/missing.svgz differ diff --git a/graphics-svg/src/test/res/round_path.svg b/graphics-svg/src/test/res/round_path.svg new file mode 100644 index 0000000..b7e9e05 --- /dev/null +++ b/graphics-svg/src/test/res/round_path.svg @@ -0,0 +1,20 @@ + + + + +]> + + + + + + + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index a70f27a..464a7eb 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,5 @@ include 'graphics-png' +include 'graphics-svg' include 'graphics-vector' include 'graphics-vector-eps' include 'graphics-vector-pdf'