Open geooff opened 5 years ago
The fork mentioned in issue #89 has a more powerful SaxDocument class, that can in particular handle use
elements. Usage:
from svgpathtools import *
doc = SaxDocument()
doc.sax_parse('test.svg')
doc.set_background_color(random_color())
doc.display("test_out.svg") # saves a file named 'test_out.svg' in the current directory
However, note that elements such as circle
, rect
, ellipse
, etc, are all converted to path
elements at parse time by SaxDocument.
The actual lossless-ness there is the harder point. You'd be basically needing to save all the original content even unknown values and the original CSS to be reproduced. You can preprocess the parsing to cope with defs and use. So rather than iterparse, you use a custom generator that itself uses iterparse that pre-fixes the structure with the use elements. It's what I did with my much more powerful parser project. But, even that necessarily breaks the structure and is lossy since it just naively fixes the structure when you used use
elements. To make them properly look like circles or whatever they referenced properly in the right place.
To correct this though not the lossy version I'd recommend my fix in svgelements ( https://github.com/meerk40t/svgelements ).
@staticmethod
def svg_structure_parse(source):
"""
SVG Structure parsing parses the svg file such that it creates the structure implied by reused objects in a more
generalized context. Objects ids are read, and put into a shadow tree. <defs> objects are omitted from the
structure of the objects. And <use> objects seamlessly replaced with their definitions.
:param source: svg file source.
:generates: iterparse 'start' and 'end' values restructured.
"""
defs = {}
parent = None
children = list()
def_depth = 0
for event, elem in iterparse(source, events=('start', 'end')):
tag = elem.tag
if tag.startswith('{http://www.w3.org/2000/svg'):
tag = tag[28:] # Removing namespace. http://www.w3.org/2000/svg:
elem.tag = tag
attributes = elem.attrib
if event == 'start':
# New node.
siblings = children # Parent's children are now my siblings.
parent = (parent, children) # parent is now previous node context
children = list() # new node has no children.
node = (elem, children) # define this node.
siblings.append(node) # siblings now includes this node.
if SVG_TAG_USE == tag:
url = None
if XLINK_HREF in attributes:
url = attributes[XLINK_HREF]
if SVG_HREF in attributes:
url = attributes[SVG_HREF]
if url is not None:
transform = False
try:
transform = True
x = attributes[SVG_ATTR_X]
del attributes[SVG_ATTR_X]
except KeyError:
x = '0'
try:
transform = True
y = attributes[SVG_ATTR_Y]
del attributes[SVG_ATTR_Y]
except KeyError:
y = '0'
if transform:
try:
attributes[SVG_ATTR_TRANSFORM] = '%s translate(%s, %s)' %\
(attributes[SVG_ATTR_TRANSFORM], x,y)
except KeyError:
attributes[SVG_ATTR_TRANSFORM] = 'translate(%s, %s)' % (x, y)
yield event, elem
try:
s_elem, s_children = defs[url[1:]] # Shadow node.
except KeyError:
continue
for shadow_event, shadow_elem in SVG._shadow_iter(s_elem, s_children):
yield shadow_event, shadow_elem
continue
if SVG_ATTR_ID in attributes: # If we have an ID, save the node.
defs[attributes[SVG_ATTR_ID]] = node # store node value in defs.
if tag == SVG_TAG_DEFS:
def_depth += 1
else:
# event is 'end', pop values.
parent, children = parent # Pop off previous context.
if tag == SVG_TAG_DEFS:
def_depth -= 1
continue
if def_depth == 0:
yield event, elem
It's a bit complex since my use case is perfect generation of the intent of the SVG for use as shapes and such. But, you take the x and y values on the use
object and convert them to being transforms that are appended to the attributes. And it'll just secretly rearrange the defs to be omitted from the list iteration and will stealthily replace any use
objects with their shadow-tree equals. It might well patch directly into the SAX Parser.
The following code is taken from the README. I'm attempting to parse SVG images and then reconstruct them without any losses.
When parsed the picture is modified, images below:
Original Image
Reconstructed Image
Sorry If this can't easily be viewed I'm not sure of the best way to post SVG images to issues.
The images loses its positioning which is important for what I'm trying do. I believe the issue is occurring with the line
<use x="5" y="5" xlink:href="#myCircle"/>
where svg2paths2 is unable to understand the reference to the myCircle def from beforeRelevant Docs on defs in SVG