parsing svg file paths with python

  • Last Update :
  • Techknowledgy :

There is an svg.path module which extracts paths and other shapes plus provides methods to process them.

from xml.dom
import minidom
from svg.path
import parse_path

svg_dom = minidom.parseString(svg_string)

path_strings = [path.getAttribute('d') for path in svg_dom.getElementsByTagName('path')]

for path_string in path_strings:
   path_data = parse_path(path_string)

# now use methods provided by the path_data object
# e.g.points can be extracted using
# point = path_data.pos(pos_val)
# where pos_val is anything between 0 and 1

I have been working on the same problem my solution was this: 1.convert svg paths to polygons using http://guilhermemussi.com/conversor.html 2. use a relatively simple python script to extract a list of the points. Here is my code it might be sort of messy/inneficient but it gets the job done

scribble = open("scrib1.txt")
for line in scribble:
   if line.startswith("<polygon"):
   rightline = line.split('"')
commas = rightline[13].split(' ')
newlist = []
for i in commas:
   tup = i.split(',')
newlist.append((tup[0], tup[1]))

Suggestion : 2

There is an svg.path module which anycodings_svg extracts paths and other shapes plus anycodings_svg provides methods to process them. ,So I've gone so far in this project and the anycodings_python only problem that I am having now is to anycodings_python parse the SVG file into a list of path as a anycodings_python list of string.,That's an old thread but since the link anycodings_svg from the accepted answer no longer works anycodings_svg here is my approach to processing svg anycodings_svg paths. ,I just want to access the data inside that anycodings_python dom object as a string and when I tried

I tried minidom but it doesn't seems that anycodings_python it's working. I can actually access the SVG anycodings_python file and but I can't access the path data anycodings_python example 'M 100,200 L 200.300' instead of anycodings_python that I get

>>> from xml.dom import minidom
>>> xmldoc= minidom.parse("C:\Users\DELL\Desktop\drawing-1.svg")
>>> a=xmldoc.getElementsByTagName("svg")[0]
>>> b=a.getElementsByTagName("g")[0]
>>> pth=b.getElementsByTagName("path")[0]
>>> pth
<DOM Element: path at 0x1bb6238>

I just want to access the data inside that anycodings_python dom object as a string and when I tried

>>> print(str(pth))

There is an svg.path module which anycodings_svg extracts paths and other shapes plus anycodings_svg provides methods to process them.

from xml.dom
import minidom
from svg.path
import parse_path

svg_dom = minidom.parseString(svg_string)

path_strings = [path.getAttribute('d') for path in svg_dom.getElementsByTagName('path')]

for path_string in path_strings:
   path_data = parse_path(path_string)

# now use methods provided by the path_data object
# e.g.points can be extracted using
# point = path_data.pos(pos_val)
# where pos_val is anything between 0 and 1

I have been working on the same problem anycodings_svg my solution was this: 1.convert svg anycodings_svg paths to polygons using anycodings_svg http://guilhermemussi.com/conversor.html 2. anycodings_svg use a relatively simple python script to anycodings_svg extract a list of the points. Here is my anycodings_svg code it might be sort of anycodings_svg messy/inneficient but it gets the job anycodings_svg done

scribble = open("scrib1.txt")
for line in scribble:
   if line.startswith("<polygon"):
   rightline = line.split('"')
commas = rightline[13].split(' ')
newlist = []
for i in commas:
   tup = i.split(',')
newlist.append((tup[0], tup[1]))

Suggestion : 3

svg.path is a collection of objects that implement the different path commands in SVG, and a parser for SVG path definitions.,There is also a parse_path() function that will take an SVG path definition and return a Path object:,Lucas Simon discovered and fixed that not all path segments preserved the relative setting when parsing.,New method on path objects: .tangent(point), which returns a vector that is the derivatative / tangent of the curve at that point. [vidstige]

All coordinate values for these classes are given as complex values, where the .real part represents the X coordinate, and the .imag part representes the Y coordinate:

>>> from svg.path
import Path, Move, Line, Arc, CubicBezier, QuadraticBezier, Close

You can calculate the length of a Path or it’s segments with the .length() function. For CubicBezier and Arc segments this is done by geometric approximation and for this reason may be very slow. You can make it faster by passing in an error option to the method. If you don’t pass in error, it defaults to 1e-12:

>>> CubicBezier(300 + 100 j, 100 + 100 j, 200 + 200 j, 200 + 300 j).length(error = 1e-5)
297.2208145656899

There is also a parse_path() function that will take an SVG path definition and return a Path object:

>>> from svg.path
import parse_path
   >>>
   parse_path('M 100 100 L 300 100')
Path(Move(to = (100 + 100 j)), Line(start = (100 + 100 j), end = (300 + 100 j)))

The path object also has a d() method that will return the SVG representation of the Path segments:

>>> path.d()
'M 200,100 L 300,100 Q 200,200 200,300'
6._
>>> path
Path(Move(to = (200 + 100 j)), Line(start = (100 + 200 j), end = (300 + 100 j)),
   QuadraticBezier(start = (300 + 100 j), control = (200 + 200 j), end = (200 + 300 j),
      smooth = False))

The Path class is a mutable sequence, so it behaves like a list. You can add to it and replace path segments etc:

>>> path = Path(Move(200 + 100 j), Line(200 + 100 j, 100 + 200 j), Line(100 + 200 j, 300 + 100 j)) >>>
   path.append(QuadraticBezier(300 + 100 j, 200 + 200 j, 200 + 300 j)) >>>
   path[0] = Move(200 + 100 j) >>>
   del path[1]

The path object also has a d() method that will return the SVG representation of the Path segments:

>>> path.d()
'M 200,100 L 300,100 Q 200,200 200,300'
3._
>>> path
Path(Move(to = (200 + 100 j)), Line(start = (100 + 200 j), end = (300 + 100 j)),
   QuadraticBezier(start = (300 + 100 j), control = (200 + 200 j), end = (200 + 300 j),
      smooth = False))
>>> path
Path(Move(to = (200 + 100 j)), Line(start = (100 + 200 j), end = (300 + 100 j)),
   QuadraticBezier(start = (300 + 100 j), control = (200 + 200 j), end = (200 + 300 j),
      smooth = False))

This SVG path example draws a triangle:

>>> path1 = parse_path('M 100 100 L 300 100 L 200 300 z')

You can format SVG paths in many different ways, all valid paths should be accepted:

>>> path2 = parse_path('M100,100L300,100L200,300z')

And these paths should be equal:

>>> path1 == path2
True

And it should again be equal to the first path:

>>> path1 == path2
True

Paths are mutable sequences, you can slice and append:

>>> path1.append(QuadraticBezier(300 + 100 j, 200 + 200 j, 200 + 300 j)) >>>
   len(path1[2: ]) == 3
True

Suggestion : 4

I am working on a robotic project that from an Android running device take a picture then send to cloudconvert.org to convert it into an SVG, then all SVG paths will be translated into x y coordinates and serially send to the robotic arm which will plot them with the pen on or off.,So I've gone so far in this project and the only problem that I am having now is to parse the SVG file into a list of path as a list of string.,That's an old thread but since the link from the accepted answer no longer works here is my approach to processing svg paths. ,I just want to access the data inside that dom object as a string and when I tried

I tried minidom but it doesn't seems that it's working. I can actually access the SVG file and but I can't access the path data example 'M 100,200 L 200.300' instead of that I get

>>> from xml.dom import minidom
>>> xmldoc= minidom.parse("C:\Users\DELL\Desktop\drawing-1.svg")
>>> a=xmldoc.getElementsByTagName("svg")[0]
>>> b=a.getElementsByTagName("g")[0]
>>> pth=b.getElementsByTagName("path")[0]
>>> pth
<DOM Element: path at 0x1bb6238>

I just want to access the data inside that dom object as a string and when I tried

>>> print(str(pth))

There is an svg.path module which extracts paths and other shapes plus provides methods to process them.

from xml.dom
import minidom
from svg.path
import parse_path

svg_dom = minidom.parseString(svg_string)

path_strings = [path.getAttribute('d') for path in svg_dom.getElementsByTagName('path')]

for path_string in path_strings:
   path_data = parse_path(path_string)

# now use methods provided by the path_data object
# e.g.points can be extracted using
# point = path_data.pos(pos_val)
# where pos_val is anything between 0 and 1

Suggestion : 5

svgelements is compatible with Python 3+. Support for 2.7 was dropped at Python 2 End-Of-Life January 1, 2020.,The primary function of svgelements is to parse svg files. There are two main functions to facilitate this,The svgelements code should not include any hard dependencies. It should remain a single file with emphasis on allowing projects to merely include a copy of svgelements.py to do any SVG parsing required.,Without robust SVG parsing you'll find repeated edge cases of some svg files that do not parse correctly. svgelements aims to avoid those pitfalls with robust adherence to the SVG spec.

Fix Issue 174 b - Blank Style Tag Crash
    def parse(source,
       reify = True,
       ppi = DEFAULT_PPI,
       width = 1,
       height = 1,
       color = "black",
       transform = None,
       context = None):
       for element in svg.elements():
          try:
          if element.values['visibility'] == 'hidden':
          continue
       except(KeyError, AttributeError):
          pass
       if isinstance(element, SVGText):
          elements.append(element)
       elif isinstance(element, Path):
          if len(element) != 0:
          elements.append(element)
       elif isinstance(element, Shape):
          e = Path(element)
       e.reify() # In some cases the shape could not have reified, the path must.
       if len(e) != 0:
          elements.append(e)
       elif isinstance(element, SVGImage):
          try:
          element.load(os.path.dirname(pathname))
       if element.image is not None:
          elements.append(element)
       except OSError:
          pass
>>> Point(10, 10) * "rotate(90)"
Point(-10, 10)
>>> Matrix("rotate(100grad)")
Matrix(0, 1, -1, 0, 0, 0)
>>> Path() + "M0,0z"
Path(Move(end = Point(0, 0)), Close(start = Point(0, 0), end = Point(0, 0)))