5

I'm looking to consume an svg image and parse/process the different paths to do a custom conversion. What is the easiest way, in Java, to simply extract the path data? I was looking at the apache xmlgraphics/batik packages, but it's not real obvious how to return the path types and parameters. Any suggestions?

helderdarocha
  • 23,209
  • 4
  • 50
  • 65
end-user
  • 2,845
  • 6
  • 30
  • 56

1 Answers1

11

To simply extract the path data you can use XPath.

Suppose you have this SVG and you want to extract all the path data (from both path elements):

<svg>
  <rect x="1" y="1" width="1198" height="598"
        fill="none" stroke="blue" stroke-width="1" />

  <path d="M200,300 Q400,50 600,300 T1000,300"
        fill="none" stroke="red" stroke-width="5"  />
  <g fill="black" >
    <circle cx="200" cy="300" r="10"/>
    <circle cx="600" cy="300" r="10"/>
    <circle cx="1000" cy="300" r="10"/>
  </g>
  <g fill="#888888" >
    <circle cx="400" cy="50" r="10"/>
    <circle cx="800" cy="550" r="10"/>
  </g>
  <path d="M200,300 L400,50 L600,300 L800,550 L1000,300"
        fill="none" stroke="#888888" stroke-width="2" />
</svg>

You first load the XML as a Document:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse("image.svg");

Then you use XPath to select the desired nodes. The expression below selects the contents of the d attributes of all the path elements inside the file:

String xpathExpression = "//path/@d";

Now we can instantiate the XPath processor and compile the expression:

XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
XPathExpression expression = xpath.compile(xpathExpression);

Since the expected result is a node-set (two strings), we evaluate the expression on the SVG document using XPathConstants.NODESET as the second parameter:

NodeList svgPaths = (NodeList)expression.evaluate(document, XPathConstants.NODESET);

From there you can extract the first set of path data using:

svgPaths.item(0).getNodeValue();
helderdarocha
  • 23,209
  • 4
  • 50
  • 65
  • You're right, I could simply use XPath to parse the file. I guess what I was looking for was something to also handle the path data. In your first example, there are three SVG commands in the path data. I assumed there was something that would create a drawing sequence with those commands. – end-user Feb 24 '14 at 12:29
  • Yes. You can split by the spaces, and then extract the commands. They have a standard format. Q is for quadratic bezier specifying a control point, T is quadratic bezier continuing the curve tangencially, M is move-to, L is line-to, and so on. Some take one pair of coordinates, others take 2. You can read more about it here: http://www.w3.org/TR/SVG/paths.html which is where I took the example SVG from. – helderdarocha Feb 24 '14 at 14:32
  • I know where to find the SVG specifcation. And, yes, I *could* write a parser to decompose the path data. I was trying not to reinvent this. – end-user Feb 24 '14 at 14:36
  • To parse the path data you could use Batik's `PathParser`. From there you can apply the values to the Batik API, `GeneralPath` (from java.awt.geom) and [ExtendedGeneralPath](https://github.com/jkroso/parse-svg-path) from Batik allow you to recreate the path, and modify it. – helderdarocha Feb 24 '14 at 14:48
  • we can also modify the attributes by using above steps. But how we can save after modified the attributes? – Tara Sep 06 '22 at 10:06