SVG parser based on lxml.etree.
This project aims to implement an SVG 2 DOM API.
-
Parsing from files
>>> from svgpy import SVGParser >>> parser = SVGParser(remove_comments=True) >>> doc = parser.create_document('http://www.w3.org/2000/svg') >>> doc.location.assign('https://raw.githubusercontent.com/miute/svgpy/master/tests/svg/svg.svg') >>> print(doc.tostring(pretty_print=True).decode()) <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100" viewBox="0 0 100 100"> <g id="gtop" stroke-width="12" stroke="#000"> <g id="svgstar" transform="translate(50,50)"> <path id="svgbar" d="M-27-5a7,7,0,1,0,0,10h54a7,7,0,1,0,0-10z"/> <use id="use1" xlink:href="#svgbar" transform="rotate(45)"/> <use id="use2" xlink:href="#svgbar" transform="rotate(90)"/> <use id="use3" xlink:href="#svgbar" transform="rotate(135)"/> </g> </g> <use id="usetop" xlink:href="#svgstar" fill="#FB4"/> </svg> >>> for element in doc.document_element.iter(): ... print((element.node_type, element.node_name, element.id)) ... (1, 'svg', '') (1, 'g', 'gtop') (1, 'g', 'svgstar') (1, 'path', 'svgbar') (1, 'use', 'use1') (1, 'use', 'use2') (1, 'use', 'use3') (1, 'use', 'usetop') >>> element = doc.get_element_by_id('usetop') >>> element.attributes {'id': 'usetop', '{http://www.w3.org/1999/xlink}href': '#svgstar', 'fill': '#FB4'} >>> bbox = element.get_bbox() >>> bbox.x, bbox.y, bbox.width, bbox.height (11.101020514433644, 11.101020514433644, 77.79795897113272, 77.79795897113272) >>> element = doc.get_element_by_id('svgbar') >>> element.attributes {'id': 'svgbar', 'd': 'M-27-5a7,7,0,1,0,0,10h54a7,7,0,1,0,0-10z'} >>> bbox = element.get_bbox() >>> bbox.x, bbox.y, bbox.width, bbox.height (-38.89897948556636, -7.0000009993777565, 77.79795897113272, 14.000001998755515) >>> element.get_total_length() 173.68771160294722
-
Serialization
>>> from svgpy import SVGParser >>> parser = SVGParser() >>> doc = parser.create_svg_document() >>> root = doc.document_element >>> root.attributes.update({'width': '10cm', 'height': '3cm', 'viewBox': '0 0 1000 300'}) >>> text = doc.create_element_ns('http://www.w3.org/2000/svg', 'text') >>> root.append(text) >>> text.style.update({'font-family': 'Verdana', 'font-size': '55', 'fill': 'blue'}) >>> tspan = doc.create_element_ns('http://www.w3.org/2000/svg', 'tspan') >>> text.append(tspan) >>> tspan.attributes.update({'x': '250', 'y': '150', 'rotate': '-30,0,30'}) >>> tspan.text = 'Hello, out there' >>> print(doc.tostring(pretty_print=True).decode()) <svg xmlns="http://www.w3.org/2000/svg" width="10cm" height="3cm" viewBox="0 0 1000 300"> <text style="fill: blue; font-family: Verdana; font-size: 55;"> <tspan x="250" y="150" rotate="-30,0,30">Hello, out there</tspan> </text> </svg> >>> tree = root.getroottree() >>> tree.write('output.svg', encoding='utf-8', pretty_print=True)
$ cat output.svg <svg xmlns="http://www.w3.org/2000/svg" width="10cm" height="3cm" viewBox="0 0 1000 300"> <text style="fill: blue; font-family: Verdana; font-size: 55;"> <tspan x="250" y="150" rotate="-30,0,30">Hello, out there</tspan> </text> </svg>
-
Path processing
>>> from svgpy import PathParser, SVGParser, SVGPathSegment, formatter >>> parser = SVGParser() >>> path = parser.create_element_ns('http://www.w3.org/2000/svg', 'path') >>> path_data = list() >>> path_data.append(SVGPathSegment('M', 150, 10)) >>> path_data.append(SVGPathSegment('B', 36)) >>> path_data.append(SVGPathSegment('h', 47)) >>> path_data.append(SVGPathSegment('b', 72)) >>> path_data.append(SVGPathSegment('h', 47)) >>> path_data.append(SVGPathSegment('b', 72)) >>> path_data.append(SVGPathSegment('h', 47)) >>> path_data.append(SVGPathSegment('b', 72)) >>> path_data.append(SVGPathSegment('h', 47)) >>> path_data.append(SVGPathSegment('z')) >>> path.set_path_data(path_data) >>> path.get_attribute('d') 'M150,10 B36 h47 b72 h47 b72 h47 b72 h47 z' >>> bbox = path.get_bbox() >>> bbox.x, bbox.y, bbox.width, bbox.height (111.97620126437747, 10.0, 76.04759747124507, 72.32556312361845) >>> path.get_total_length() 235.0 >>> normalized = PathParser.normalize(path_data) # convert to 'M', 'L', 'C' and 'Z' path command >>> path.set_path_data(normalized) >>> path.get_attribute('d') 'M150,10 L188.023799,37.625907 173.5,82.325563 126.5,82.325563 111.976201,37.625907 Z' >>> formatter.precision 6 # default precision for a floating point value >>> formatter.precision = 3 >>> path.set_path_data(normalized) >>> path.get_attribute('d') 'M150,10 L188.024,37.626 173.5,82.326 126.5,82.326 111.976,37.626 Z' >>> bbox = path.get_bbox() >>> bbox.x, bbox.y, bbox.width, bbox.height (111.976, 10.0, 76.048, 72.326) >>> path.get_total_length() 235.00121335747357
This software is licensed under the Apache License 2.0.