Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何以编程方式在SVG文件中进行组转换?_Java_Svg_Batik - Fatal编程技术网

Java 如何以编程方式在SVG文件中进行组转换?

Java 如何以编程方式在SVG文件中进行组转换?,java,svg,batik,Java,Svg,Batik,我有以下图像的SVG文件: 每个箭头由如下代码表示: <g transform="matrix(-1,0,0,-1,149.82549,457.2455)" id="signS" inkscape:label="#sign"> <title id="title4249">South, 180</title> <path sodipodi:nodetypes="ccc" inkscape:conne

我有以下图像的SVG文件:

每个箭头由如下代码表示:

<g
   transform="matrix(-1,0,0,-1,149.82549,457.2455)"
   id="signS"
   inkscape:label="#sign">
  <title
     id="title4249">South, 180</title>
  <path
     sodipodi:nodetypes="ccc"
     inkscape:connector-curvature="0"
     id="path4251"
     d="m 30.022973,250.04026 4.965804,-2.91109 4.988905,2.91109"
     style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.6855976px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
  <rect
     y="250.11305"
     x="29.768578"
     height="2.6057031"
     width="10.105703"
     id="rect4253"
     style="fill:#008000;fill-opacity:1;stroke:#000000;stroke-width:0.53715414;stroke-opacity:1" />
</g>
据我所知,
doc
可以转换为

如何从SVG文档获取矩形或组的绝对位置

注意:我需要一些现有的代码,这些代码执行上述转换(不要告诉我自己实现这些转换-它们必须已经实现,我想重新使用这些代码)

更新1(08.11.2015 12:56 MSK):

实施Robert Longson建议的第一次尝试:

public final class BatikTest {
    @Test
    public void test() throws XPathExpressionException {
        try {
            final File initialFile =
                new File("src/main/resources/trailer/scene05_signs.svg");
            InputStream sceneFileStream = Files.asByteSource(initialFile).openStream();


            String parser = XMLResourceDescriptor.getXMLParserClassName();
            SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
            String uri = "http://www.example.org/diagram.svg";
            final SVGOMDocument doc = (SVGOMDocument) f.createDocument(
                uri, sceneFileStream);

            final NodeList nodes =
                doc.getDocumentElement().getElementsByTagName("g");
            SVGOMGElement signSouth = null;


            for (int i=0; (i < nodes.getLength()) && (signSouth == null); i++) {
                final Node curNode = nodes.item(i);
                final Node id = curNode.getAttributes().getNamedItem("id");
                if ("signS".equals(id.getTextContent())) {
                    signSouth = (SVGOMGElement) curNode;
                }

                System.out.println("curNode: " + nodes);
            }
            System.out.println("signSouth: " + signSouth);

            final NodeList rectNodes = signSouth.getElementsByTagName("rect");
            System.out.println("rectNodes: " + rectNodes);

            SVGOMRectElement rectNode = (SVGOMRectElement) rectNodes.item(0);

            System.out.println("rectNode: " + rectNode);

            final SVGMatrix m2 =
                signSouth.getTransformToElement(rectNode);

            System.out.println("m2: " + m2);
        } catch (IOException ex) {
            Assert.fail(ex.getMessage());
        }
    }
}
结果:

java.lang.NullPointerException
    at org.apache.batik.dom.svg.SVGLocatableSupport$3.getAffineTransform(Unknown Source)
    at org.apache.batik.dom.svg.AbstractSVGMatrix.getA(Unknown Source)
    at org.apache.batik.dom.svg.SVGOMPoint.matrixTransform(Unknown Source)
    at org.apache.batik.dom.svg.SVGOMPoint.matrixTransform(Unknown Source)
    at [...].BatikTest.test(BatikTest.java:77)
更新3,赏金条款(MSK 2015年11月10日):

获得赏金必须满足的条件:

我将把奖金奖励给英雄或女英雄,他们设法在JUnit测试中实现了方法
magicallyCalculateXCoordinate
magicallycalculatecoordinate
,这样我就可以在Java代码中获得在InkScape中显示的形状坐标(参见下面的屏幕截图)

所提出的计算SVG文件中形状位置的方法也必须有效

  • 对于组节点(如图中和中的节点)或
  • 对于三角形
  • 您提供的代码必须适用于示例文件中的所有四种形状,即。E使用它,我必须能够在Java代码中计算它们的坐标,这些坐标等于在Inkscape中显示的坐标

    您可以向方法
    magicallyCalculateXCoordinate
    magicallyCalculateXCoordinate
    添加参数,还可以创建自己的方法来计算坐标

    您可以使用任何合法用于商业目的的图书馆


    与此请求相关的所有文件都可以在上找到。我设法用IntelliJ Idea社区版14.1.5编写了测试。

    我知道,我参加聚会迟到了,但我偶然发现了这个问题,并喜欢这个谜语;-)

    svg中的原点是左上角,而inkscape使用左下角作为原点

    所以我们需要应用笔划和变换,然后找到左下角的点,四舍五入到三位小数。 我使用GVTBuilder获取具有应用样式的边界框,然后转换边界框,请求转换组的边界框,然后使用xMin和yMax作为参考点。使用viewbox来确定高度,我转换了y坐标,最后将坐标四舍五入。 (请参阅github上的pull请求)

    package test.java.svgspike;
    导入org.apache.batik.anim.dom.SAXSVGDocumentFactory;
    导入org.apache.batik.anim.dom.SVGOMDocument;
    导入org.apache.batik.anim.dom.SVGOMGElement;
    导入org.apache.batik.bridge.BridgeContext;
    导入org.apache.batik.bridge.GVTBuilder;
    导入org.apache.batik.bridge.UserAgentAdapter;
    导入org.apache.batik.gvt.GraphicsNode;
    导入org.apache.batik.util.XMLResourceDescriptor;
    导入javax.xml.xpath.XPathExpressionException;
    导入java.awt.geom.Point2D;
    导入java.awt.geom.Path2D;
    导入java.awt.geom.Rectangle2D;
    导入java.io.File;
    导入java.io.IOException;
    导入java.io.InputStream;
    导入java.math.BigDecimal;
    导入com.google.common.io.Files;
    导入org.junit.Assert;
    导入org.junit.Test;
    导入org.w3c.dom.Node;
    导入org.w3c.dom.NodeList;
    /**
    *由pisarenko于2015年11月10日创建。
    */
    公开期末班蜡染测试{
    @试验
    public void test()抛出XPathExpressionException{
    试一试{
    最终文件初始文件=
    新文件(“src/test/resources/scene05_signs.svg”);
    InputStream sceneflestream=Files.asByteSource(initialFile.openStream();
    字符串解析器=XMLResourceDescriptor.getXMLParserClassName();
    SAXSVGDocumentFactory f=新的SAXSVGDocumentFactory(解析器);
    字符串uri=”http://www.example.org/diagram.svg";
    最终SVGOMDocument文档=(SVGOMDocument)f.createDocument(
    uri,场景流);
    字符串viewBox=doc.getDocumentElement().getAttribute(“viewBox”);
    Point2D referencePoint=getReferencePoint(文档,getGroupElement(文档,“符号”);
    双符号SouthX=MagicallyCalculateX坐标(参考点);
    双符号southy=magicallyCalculateYCoordinate(参考点,视图框);
    Assert.assertEquals(109.675,signSouthX,0.0000001);
    Assert.assertEquals(533.581,signSouthY,0.0000001);
    referencePoint=getReferencePoint(doc,getGroupElement(doc,signN));
    Assert.assertEquals(109.906,magicallyCalculateXCoordinate(referencePoint),0.0000001);
    Assert.assertEquals(578.293,magicallyCalculateYCoordinate(referencePoint,viewBox),0.0000001);
    referencePoint=getReferencePoint(doc,getGroupElement(doc,signE));
    Assert.assertEquals(129.672,magicallyCalculateXCoordinate(referencePoint),0.0000001);
    Assert.assertEquals(554.077,magicallyCalculateYCoordinate(referencePoint,viewBox),0.0000001);
    referencePoint=getReferencePoint(doc,getGroupElement(doc,signW));
    Assert.assertEquals(93.398,magicallyCalculateXCoordinate(referencePoint),0.0000001);
    Assert.assertEquals(553.833,magicallyCalculateYCoordinate(referencePoint,viewBox),0.0000001);
    }捕获(IOEX异常){
    Assert.fail(例如getMessage());
    }
    }
    私有SVGOMGElement getGroupElement(SVGOMDocument文档,字符串id){
    最终节点列表节点=doc.getDocumentElement().getElementsByTagName(“g”);
    SVGOMGElement signGroup=null;
    对于(inti=0;(ifinal SVGSVGElement docElem = (SVGSVGElement)
        doc.getDocumentElement();
    final SVGPoint svgPoint = docElem.createSVGPoint();
    svgPoint.setX((float) x);
    svgPoint.setY((float) y);
    final SVGPoint svgPoint1 =
        svgPoint.matrixTransform(signSouth.getScreenCTM()); // Line 77
    
    System.out.println("x: " + svgPoint1.getX());
    System.out.println("y: " + svgPoint1.getY());
    
    java.lang.NullPointerException
        at org.apache.batik.dom.svg.SVGLocatableSupport$3.getAffineTransform(Unknown Source)
        at org.apache.batik.dom.svg.AbstractSVGMatrix.getA(Unknown Source)
        at org.apache.batik.dom.svg.SVGOMPoint.matrixTransform(Unknown Source)
        at org.apache.batik.dom.svg.SVGOMPoint.matrixTransform(Unknown Source)
        at [...].BatikTest.test(BatikTest.java:77)
    
    package test.java.svgspike;
    
    import org.apache.batik.anim.dom.SAXSVGDocumentFactory;
    import org.apache.batik.anim.dom.SVGOMDocument;
    import org.apache.batik.anim.dom.SVGOMGElement;
    import org.apache.batik.bridge.BridgeContext;
    import org.apache.batik.bridge.GVTBuilder;
    import org.apache.batik.bridge.UserAgentAdapter;
    import org.apache.batik.gvt.GraphicsNode;
    import org.apache.batik.util.XMLResourceDescriptor;
    
    import javax.xml.xpath.XPathExpressionException;
    
    import java.awt.geom.Point2D;
    import java.awt.geom.Path2D;
    import java.awt.geom.Rectangle2D;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.math.BigDecimal;
    
    import com.google.common.io.Files;
    
    import org.junit.Assert;
    import org.junit.Test;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;
    
    /**
     * Created by pisarenko on 10.11.2015.
     */
    public final class BatikTest {
    
        @Test
        public void test() throws XPathExpressionException {
            try {
                final File initialFile =
                        new File("src/test/resources/scene05_signs.svg");
                InputStream sceneFileStream = Files.asByteSource(initialFile).openStream();
    
                String parser = XMLResourceDescriptor.getXMLParserClassName();
                SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
                String uri = "http://www.example.org/diagram.svg";
                final SVGOMDocument doc = (SVGOMDocument) f.createDocument(
                        uri, sceneFileStream);
    
                String viewBox = doc.getDocumentElement().getAttribute("viewBox");
    
                Point2D referencePoint = getReferencePoint(doc, getGroupElement(doc, "signS"));
    
                double signSouthX = magicallyCalculateXCoordinate(referencePoint);
                double signSouthY = magicallyCalculateYCoordinate(referencePoint, viewBox);
    
                Assert.assertEquals(109.675, signSouthX, 0.0000001);
                Assert.assertEquals(533.581, signSouthY, 0.0000001);
    
                referencePoint = getReferencePoint(doc, getGroupElement(doc, "signN"));
                Assert.assertEquals(109.906, magicallyCalculateXCoordinate(referencePoint), 0.0000001);
                Assert.assertEquals(578.293, magicallyCalculateYCoordinate(referencePoint, viewBox), 0.0000001);
    
                referencePoint = getReferencePoint(doc, getGroupElement(doc, "signE"));
                Assert.assertEquals(129.672, magicallyCalculateXCoordinate(referencePoint), 0.0000001);
                Assert.assertEquals(554.077, magicallyCalculateYCoordinate(referencePoint, viewBox), 0.0000001);
    
                referencePoint = getReferencePoint(doc, getGroupElement(doc, "signW"));
                Assert.assertEquals(93.398, magicallyCalculateXCoordinate(referencePoint), 0.0000001);
                Assert.assertEquals(553.833, magicallyCalculateYCoordinate(referencePoint, viewBox), 0.0000001);
    
    
            } catch (IOException ex) {
                Assert.fail(ex.getMessage());
            }
        }
    
        private SVGOMGElement getGroupElement(SVGOMDocument doc, String id){
            final NodeList nodes = doc.getDocumentElement().getElementsByTagName("g");
            SVGOMGElement signGroup = null;
            for (int i=0; (i < nodes.getLength()) && (signGroup == null); i++) {
                final Node curNode = nodes.item(i);
                final Node idNode = curNode.getAttributes().getNamedItem("id");
                if (id.equals(idNode.getTextContent())) signGroup = (SVGOMGElement) curNode;
            }
            return signGroup;
        }
    
        /**
         * @param doc
         * @param signGroup
         * @return the reference point, inkscape uses for group (bottom left corner of group)
         */
        private Point2D getReferencePoint(SVGOMDocument doc, SVGOMGElement signGroup){
    
            Point2D referencePoint = new Point2D.Double(0, 0);
    
            try {
    
                BridgeContext ctx = new BridgeContext(new UserAgentAdapter());
                new GVTBuilder().build(ctx, doc);
                GraphicsNode gvtElement = new GVTBuilder().build(ctx, signGroup);
    
                Rectangle2D rc = gvtElement.getSensitiveBounds();
                rc = ((Path2D) gvtElement.getTransform().createTransformedShape(rc)).getBounds2D();
    
              //find xMin and yMax in poi
                referencePoint = new Point2D.Double(rc.getMinX(), rc.getMaxY());
    
            } catch (Exception e) {
                e.printStackTrace();
            }
            return referencePoint;
        }
    
        /**
         * inkscape states y coordinate with origin in left bottom corner, while svg uses top left corner as origin
         * @param referencePoint bottom left corner of group
         * @param viewBox in "originX originY width height" notation
         * @return corrected y coordinate, rounded to three decimal figures (half up)
         */
        private double magicallyCalculateYCoordinate(Point2D referencePoint, String viewBox) {
            String[] viewBoxValues = viewBox.split(" ");
            BigDecimal roundedY = new BigDecimal(Double.parseDouble(viewBoxValues[3])-referencePoint.getY());
            roundedY = roundedY.setScale(3, BigDecimal.ROUND_HALF_UP);
            return roundedY.doubleValue();
        }
    
        /**
         * @param referencePoint bottom left corner of group
         * @return x coordinate, rounded to three decimal figures (half up)
         */
        private double magicallyCalculateXCoordinate(Point2D referencePoint) {
            BigDecimal roundedX = new BigDecimal(referencePoint.getX()).setScale(3, BigDecimal.ROUND_HALF_UP);
            return roundedX.doubleValue();
        }
    
    }