meerk40t / svgelements

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

How to use svgelements to calculate the correct svg viewBox #243

Open Emasoft opened 10 months ago

Emasoft commented 10 months ago

I want to use svgelements to fix some svg files that are generated by a program.

Those svg files are missing the viewBox:

Here is an example svg file: https://gist.github.com/Emasoft/ccce2973465c2c0a6b165d1135efe1e1

Can svgelements compute the correct viewBox so that when displayed in the browser the above gist will shows the full image, with the right aspect ratio and no empty space?

I tried with the .bbox() method, but the values when used as viewBox values are still wrong. Only a part of the image is shown.

I read that you need to flatten the transforms concatenating all matrix, but how can I do that with svgelements?

tatarize commented 10 months ago

Those svgs aren't broken. The value of an svg without a viewbox is well defined. Namely it is viewed at a 1:1 value without any viewbox transformations. The spec is quite clear that is permitted and nothing is wrong with the svg since they do not actually require a viewbox.

You could probably calculate the bounding box of a particular set of elements. I think .bbox(). But, that's a bit different than you'd probably want.

You can't stop it from flattening all the transforms and concatenating all the matrices, that happens automatically and you can't stop it. I have a planned second project to fix that as an issue. These svgs have no matrix as far as you showed me.

The correct viewbox for your svg that is essentially identical to an svg without a viewbox is actually viewbox="0 0 400 400" because regardless of the actual physical size of the stuff inside you've stated within the svg that the height and width are 400px. So really a viewbox going from 0,0 to 400,400 is going to give you a 1:1 viewbox since 400 and 400 are your width and height by declaration.

svgtest

svgtest

Emasoft commented 10 months ago

I see only a white image. Where is the content? I'm pretty sure that the viewBox is not 400x400, since those values have been added by me completely at random. Those height and width values have no real relation with the content anyway, those are just defining the bitmap area used to draw the scaled version of the svg content, and are completely optional since the parent container of an html page will override them anyway. The viewBox is necessary instead. But if the viewBox does not include the content, we are looking at empty space, no matter what resolution we give to the render surface bitmap. The viewBox is like a window over the vector content. If the window is smaller than the content, or it is looking far too left or far too right, we see only a small part or even nothing (like in this case). I have no idea what the real size of the content is, where it is the beginning point and where is the end. But this is exacly what I was looking svgelements for: to calculate the bounding box. Luckily this svg file has no matrices, so we don't need to flatten the transforms before computing the bbox. But in the end it seems that it does not calculate it correctly. This is why I asked for your help.

tatarize commented 10 months ago

Took me a bit. Yes, setting the viewbox equal to the bounding box is correct.

t-correct

>>print(SVG.parse("svgtest.svg")[0].bbox())
(0.0, 0.0, 5740.0, 10240.0)

Adding into the above file viewBox="0 0 5740 10240" corrected it.