Open Emasoft opened 7 years ago
What does it do? If you mean applying transforms to paths then SVGO already does that when it possible.
It flattens the transforms of all elements (including elliptical arcs, gradients, text and tspan) concatenating the cumulative transforms of all parents since the root node and applying the resulting matrix to the leaf elements (rects are converted to polygons to allow that). When not possible to completely eliminate the transform (for edge cases like some filters on groups), the children element is left with a transform matrix that includes all transformations of the parents, so that the matrix multiplications required to get the the element local coordinates are minimized.
Well, SVGO does something of that.
It does a very little of this, actually. Transforms in the output file are still too many compared to Affinity Designer exported svg file.
It'd be more helpful if you provide such examples. Also, there was a bunch of bugs with incorrectly moved transforms, so one need to be careful with them.
Here's some examples of what I think @Emasoft is talking about:
Input:
<svg>
<g transform="translate(2.240000, 10.453333)">
<rect fill="#000" x="210.56" y="94.359" width="22.811" height="33.2" rx="3.733"/>
<rect fill="#FFF" x="210.56" y="94.359" width="22.811" height="33.2" rx="3.733"/>
</g>
</svg>
Output:
<svg>
<g transform="translate(2.24 10.453)">
<rect x="210.56" y="94.359" width="22.811" height="33.2" rx="3.733"/>
<rect fill="#FFF" x="210.56" y="94.359" width="22.811" height="33.2" rx="3.733"/>
</g>
</svg>
Should be:
<svg>
<rect x="212.80" y="104.812" width="22.811" height="33.2" rx="3.733"/>
<rect fill="#FFF" x="212.80" y="104.812" width="22.811" height="33.2" rx="3.733"/>
</svg>
Input:
<svg>
<g transform="translate(2.240000, 10.453333)">
<rect fill="#000" x="210.56" y="94.359" width="22.811" height="33.2" rx="3.733"/>
</g>
</svg>
Output:
<svg>
<rect x="210.56" y="94.359" width="22.811" height="33.2" rx="3.733" transform="translate(2.24 10.453)"/>
</svg>
Should be:
<svg>
<rect x="212.80" y="104.812" width="22.811" height="33.2" rx="3.733"/>
</svg>
Any update on this? This is a much needed feature because it allows to copy paste any xml node from an svg file to inline html without having to copy all parents nodes.
I'm planning such an operation, but no updates yet.
+1
How long before this is implemented? This is a much needed feature. Too much time wasted in doing this manually every day.
I'm afraid not so soon. It's trivial enough, but I have no time for this.
@GreLI I hope you get time to get this important feature implemented very sooooooooooooon. 😊
would also be useful to convert svg graphics to simple paths, which can easily be used in react-native-svg
seems theres an existing package https://github.com/stadline/svg-flatten to do it, maybe someone could transform this into an svgo plugin? btw the package does not seem to handle filters, maybe we should add a clause in the recursion to flatten the transform onto the filter as well. besides filters, are there any other cases where we might need to recurse transform flattening beyond a nodes children? masks maybe?
I wrote code to flatten transforms for my own project, in case anyone wants to port it over. It doesn't quite support all possible transforms on all shapes yet, but it's a start.
Another day, another starting point, my fork https://github.com/lemnis/svgo has support of removing translate
of a select group of properties. It also has the tests of above mentioned code written by @steadicat, currently my code fails most of the tests and I am not planning to improve my code in the near future.
Almost a year passed and we are still waiting. 😞
@nashwaan Be grateful that other people are willing to use their precious time to create and extend code that everybody can use. Otherwise, you have 2 options, pay lots of money more for all software you use or create the code yourself.
Or maybe the last solution is the best for you, keep waiting patiently. 😉
@lemnis Thank you for educating me and telling me I should be grateful to the open source community.
I've had the same issue, it would be really nice to be able to flatten everything.
+1 this would be awesome.
I have this issue too, and I'd swear it used to work better. But currently SVGO doesn't "flatten" or precalculate even very simple transforms. I have examples where there's a transform
translate
of 1,1
on a g
roup and even that isn't recalculated.
One very common source of unnecessary transformations stems from the behavior of design software for working with SVGs. They tend to be very literal. If you click the "path" tool, you get a path
. If you click the "circle" tool, you get a circle
. And if you draw an icon with some shapes, group them, then move it down with the arrow key 4
times and to the right 8
times, you'll end up with a g
roup that has a transform
translate
of 8, 4
. (This is true of every single editor I've used: Illustrator, Sketch, Inkscape, etc--though some of them offer ways to flatten the transforms. Sketch, however, [which we use] doesn't.)
As the OP mentions, this is just noise--there's no reason whatsoever to preserve a transformation of that kind and so files that preserve this are missing an obvious if relatively minor optimization.
But in my situation this leads to real issues. I have a use case where we need to convert our icons to Android's Vector Drawable format. We work with SVG as the "origin" format and convert to Vector Drawable after optimizing with SVGO. Vector Drawables are a little touchy, it seems (we had issues if we optimized away leading 0
s), and there aren't many tools available to automate this conversion.
And, it turns out, these preserved translations also cause issues. They're unsupported or just ignored in the conversion process and result in the icon being mis-aligned and cut off relative to the viewbox
.
@Emasoft, recently I made this repo, just like SVGOMG but with Vue. I added flatten svg option, whose code was provided by Timo in his gist (with some modifications). It is still in experimental stage. It worked on the transforms of most of the paths (except some text and clipaths). So can anyone check that option and give your opinions.
Thank you all.
@upendra-web Superb work with lean-SVG !
@upendra-web Superb work with lean-SVG !
Thank you very much @andrewrcollins
Lean-SVG still doesn't work with rect and circle. It's been 3 years, and I can see you put an enormous amount of effort in SVGO, so why not finish it with transform applying?
If you are using Inkscape:
In all cases I have tried, this has removed any transform attributes, then I can run through SVGO without having to worry about transforms. Not sure if it works for all SVG, but certainly the ones I have tried so far.
@maxwell8888 this works well for some elements, but not all unfortunately.
Some very tricky ones are:
I realise that the status of this is not likely to change, but I would love to know if it does (or if anyone finds a suitable workaround).
I've been able to apply transforms to path elements manually using stadline/svg-flatten provided that the transform attribute was associated with the path element itself (and not a group) by running in the nodejs interpreter (inside the project directory):
var flatten = require('./')
var svg = fs.readFileSync('./logo.svg')
flatten(svg).transform().value().toString()
However, this doesn't work as far as preserving the gradients if they have been defined with gradientUnits="userSpaceOnUse"
. If such a gradient is specified as a fill then the gradient also needs to have the transform applied to it. I imagine this applies to patterns as well.
I really hope this eventually comes in SVGO, I'm relying on Lean-SVG for my day-to-day work right now, but I'd love SVGO to handle everything. I think most of the debate earlier was about the reliability of the transforms, but as long as it's clear that it's an opt-in one, I can't see why not.
Could we perhaps use Inkscape CLI to ungroup elements with a transform attribute on the group, then regroup them without the transform? That should help remove the transforms.
I had an auto-generated svg with a transform="matrix(1.5,0,0,1.5,0,0)"
on the outer group with only paths inside it. I was looking for a way to perform that translation on each path ahead of time so I could remove the transform
, which is how I found this thread.
I was able to accomplish this manually by using either of these tools:
If you don't need an automated solution, these both offer a quick way to apply computations to path data.
BTW, it's good starter task, if someone would like to help.
I just thought about solving this here: https://stackoverflow.com/a/75964763/20009330
I am not saying that this solves this problem for svgo. But maybe writing a quick script (like mentioned at the bottom of the answer) to edit the svg is a workaround for some of you that come here?
The solution above only works with translate transforms...
A better solution, also for matrix transforms: maybe think: how do they even appear? Maybe prevent them from entering your svg in the first place?
Inkscape: in Inkscape, if you select all elements, it'll select groups and not all single elements. Then if you scale etc., it'll likely apply a matrix transform (to the group). We do not want this!
Solution: Select all single elements without their group folders. And then apply the transform, you'll see, Inkscape will directly apply any transforms if you do the transform operation on the children elements themselves. So, how to select ALL single elements?
GPT-4 told me this: ctrl. + f to find all.
THEN: deselect group elements in advanced search options
then just search with empty input, it'll select all
Here is a screenshot:
Has this been solved now?
@mattsputnikdigital PRs are welcome
https://github.com/svg/svgo/pull/1854 may handle this?
There are multiple implementations out there, but still, it would be really nice to have in svgo as well.
"Flatten Transforms" option is available in SVG editors like Affinity Designer (~$40 / Mac) and it is very useful. It also improve performances of SVG rendering because coordinate transforms are precalculated.
Please add this option to SVGO.