37

I want to parse an SVG file using python to extract coordinates/paths (I believe this is listed under the "path" ID, specifically the d="..."/>). This data will eventually be used to drive a 2 axis CNC.

I've searched on SO and Google for libraries that can return the string of such paths so I can further parse it, but to no avail. Does such a library exist?

3 Answers3

42

Ignoring transforms, you can extract the path strings from an SVG like so:

from xml.dom import minidom

doc = minidom.parse(svg_file)  # parseString also exists
path_strings = [path.getAttribute('d') for path
                in doc.getElementsByTagName('path')]
doc.unlink()
icktoofay
  • 126,289
  • 21
  • 250
  • 231
  • 2
    Do you have any suggestions for when transformations are important? – Veech Jun 29 '15 at 21:07
  • 1
    @Veech: If there is a transform, it is probably important. Unfortunately it takes a *lot* more code to handle them. – icktoofay Jul 02 '15 at 23:08
  • 2
    Yeah, I've come to realize that. I've found that [cjlano's svg repo](https://github.com/cjlano/svg) to be good enough (with some modifications). – Veech Jul 03 '15 at 03:36
  • Not every valid XML is a valid SVG. – Danon Jul 17 '21 at 12:38
16

Getting the d-string can be done in a line or two using svgpathtools.

from svgpathtools import svg2paths
paths, attributes = svg2paths('some_svg_file.svg')

paths is a list of svgpathtools Path objects (containing just the curve info, no colors, styles, etc.). attributes is a list of corresponding dictionary objects storing the attributes of each path.

To, say, print out the d-strings then...

for k, v in enumerate(attributes):
    print(v['d'])  # print d-string of k-th path in SVG
mathandy
  • 1,892
  • 25
  • 32
13

The question was about extracting the path strings, but in the end the line drawing commands were wanted. Based on the answer with minidom, I added the path parsing with svg.path to generate the line drawing coordinates:

#!/usr/bin/python3
# requires svg.path, install it like this: pip3 install svg.path

# converts a list of path elements of a SVG file to simple line drawing commands
from svg.path import parse_path
from svg.path.path import Line
from xml.dom import minidom

# read the SVG file
doc = minidom.parse('test.svg')
path_strings = [path.getAttribute('d') for path
                in doc.getElementsByTagName('path')]
doc.unlink()

# print the line draw commands
for path_string in path_strings:
    path = parse_path(path_string)
    for e in path:
        if isinstance(e, Line):
            x0 = e.start.real
            y0 = e.start.imag
            x1 = e.end.real
            y1 = e.end.imag
            print("(%.2f, %.2f) - (%.2f, %.2f)" % (x0, y0, x1, y1))
Carson
  • 6,105
  • 2
  • 37
  • 45
Frank Buss
  • 714
  • 7
  • 14
  • 2
    That is what I want! ``svg.path`` is more readable than ``svgpathtools``, but ``svgpathtools`` packaged well. If you want to understand how to draw the curve by the SVG file then you can read ``svg.path``, but use it with ``svgpathtools`` – Carson Dec 11 '19 at 08:15