mathandy / svgpathtools

A collection of tools for manipulating and analyzing SVG Path objects and Bezier curves.
MIT License
532 stars 134 forks source link

Getting Bounding Box of entire SVG file #181

Closed DoubleF3lix closed 2 years ago

DoubleF3lix commented 2 years ago

I've loaded in an SVG file using this:

from svgpathtools import svg2paths
paths, attr = svg2paths("testing.svg")

And I see that I have a list of paths, but how can I calculate the overall bounding box from these? The only source of data I see that matches loading in the SVG into a browser and using svg_dom.getBBox() is paths[-1][1] has the correct width if we subtract the y value.

mathandy commented 2 years ago

Does Path(*[seg for path in paths for seg in path]).bbox() work?

DoubleF3lix commented 2 years ago

Sadly not. This outputs (0.0, 643.0, -633.0, 1195.0) while document.getElementById("bbox").getBBox() gives me { x: 0.0714000016450882, y: 1.000000238418579, width: 28.39109992980957, height: 16.946998596191406 }

mathandy commented 2 years ago

Sounds like a bug. Please attach an SVG example if you can.

DoubleF3lix commented 2 years ago

testing Here you go! (Sorry it's a little large, but it's actually why I need the bounding box so I can crop it properly)

mathandy commented 2 years ago

The issue is caused by svg2paths ignoring transforms. You can use Document to respect transforms.

from svgpathtools import Document, Path, polygon

doc = Document('testing.svg')

xmin, xmax, ymin, ymax = Path(*[seg for path in doc.paths() for seg in path]).bbox()
box = polygon(xmin+ymin*1j, xmax+ymin*1j, xmax+ymax*1j, xmin+ymax*1j)

doc.add_path(box, attribs={'stroke':"red", 'stroke-width':'0.1', 'fill': 'none'})

doc.save('testing2.svg')

# fix for issue #182
with open('testing2.svg') as f:
    txt = f.read().replace('<path', '<svg:path')
with open('testing2.svg', 'w') as f:
    f.write(txt)

Result: (Note that I believe the bounding box is correct and that the bits that appear outside the box are caused by the "thickness" of the paths. As this package was designed for scientific analysis, bounding boxes are based on the 1D location of paths, ignoring how thick they look when rendered. That said, it'd be a nice feature to have a built-in workaround for this.) test2

DoubleF3lix commented 2 years ago

Thank you so much! Not related to the issue, but would you by any chance how to convert this new bounding box data to the height, width, and viewbox portions of the SVG to effectively "crop" it?

EDIT: Nevermind, I found I can remove the mm from the height and width parameters, and then just set viewbox to 0 0 height width