meerk40t / svgelements

SVG Parsing for Elements, Paths, and other SVG Objects.
MIT License
124 stars 28 forks source link

SVG width and height units are not preserved after parsing #235

Open robinwersich opened 1 year ago

robinwersich commented 1 year ago

When parsing an SVG that has a width/height with a unit, this Length is transformed to a numerical value. When writing the SVG, the unit information is lost and transform attributes are added to the elements to compensate for the changed dimensions.

While this behavior can be desired, I think there are many use cases where it is favorable to preserve the units and not add any transform attributes - for example if the written SVG should be read by another piece of software where PPI can't be specified and it is crucial to keep the real-world sizes as-is.

It would be nice to have the option to preserve units when parsing the SVG. As writing elements with units now works properly (#228), I think this can easily be implemented by just omitting the render() call. I Imagine something like this:

<svg height="20mm" version="1.1" width="20mm" viewBox="10 10 20 20" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink">
  <rect x="10" y="10" width="20" height="20"/>
</svg>
parsed_svg = SVG.parse("path/to/file.svg", render=False)
expected_svg = SVG(width="20mm", height="20mm", viewBox="10 10 20 20")
expected_svg.append(Rect(x=10, y=10, width=20, height=20))
tatarize commented 1 year ago

With render disabled it hits a value error trying to calculate the viewbox_transform.

This seems like it's more involved and might need to be pushed to meerk40t/svgio basically in #87, I realized a lot of the structures were are sort of wrong. Really rather than performing rendering during the parsing it should rather do that as a different step at a different time. You should be able to parse a bunch of svg nodes, and then alter them in any way you want and save them out. And only when you need the actual geometry should you render them and perform the render on the node tree rather than the svg.

This would enable not only this with full end-to-end modification but could allow you to go ahead and alter the nodes you want and then render it and get different results. So if you change the transform on a group that should reflect on all the subgroups seamlessly. As is, since you are forced to render to graphical objects from the get-go you can't do these changes or that sort of composing. Rather you should be allowed to do much more reasonable composition of the svgs. And when you need to actually get the shapes go ahead and render that to paths but only when you finally want them rendered, and render them multiple times with whatever changes you applied to the node structure.

So you'd basically go: file -> parse() -> dom-tree --> render() --> paths