Closed Enter-tainer closed 7 months ago
x="30" y="20"
is not a transform, but a position. Those are separate concepts in SVG.
But rect
would be converted into path
, which has a bounding box, not a position.
I would suggest using Node::abs_bounding_box
instead. This way you don't have to worry about transforms at all.
Thank you for your reply! abs_bounding_box
is great. One thing annoying is that I cannot generate an affine transform from it. Take this svg for example:
<svg viewBox="0 0 100 100" width="100" height="100" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml">
<path d="M 10 10 H 90 V 90 H 10 Z" fill="transparent" stroke="black" />
</svg>
It is a 80 * 80 rect at (10, 10). And its bbox is Rect { left: 10.0, top: 10.0, right: 90.0, bottom: 90.0 }
. To render it correctly, I shouldn't use left: 10, top: 10
as a translate transform, otherwise the top-left of the rect would be put at (20, 20) other than (10, 10). I wonder if it is possible to get such a transformation or there is better way to get the "abs_transform + position"(I hope this is what i need to transform each element to the correct position) of each element in an svg tree.
BTW, I'm trying to update vello_svg's usvg depedency from 0.37 to latest. It currently use abs_transform
to get "abs_transform + position". But i guess api has changed since then.
You don't need to know shape/path/rect position to render it. Meaning you don't need left: 10, top: 10
at all. All you need is abs_transform
.
And while API did changed, you still can use abs_transform
. It should return the same value as before.
Thank you for mentioning that. I just played with some svg and i finally learned that for <path x=...> ...
, the position is baked in the path and it is not a transform. They work the same in 0.40 and 0.37.
However for <use x=...>
, 0.40 produce different result from 0.37.
It seems that 0.40 doesn't take the position of use
into account in abs_transform
.
```rust // usvg 0.37 use usvg::{NodeExt, Options, TreeParsing}; fn main() { let svg = r##" "##; let tree = usvg::Tree::from_str(&svg, &Options::default()).unwrap(); for node in tree.root.descendants() { if let usvg::NodeKind::Path(path) = &*node.borrow() { println!("path abs_transform: {:?}", node.abs_transform()); println!("path: {:?}", path.data); } } // OUTPUT: // // path abs_transform: Transform { sx: 1.0, kx: 0.0, ky: 0.0, sy: 1.0, tx: 0.0, ty: 0.0 } // path: Path { segments: "M 0 0 L 10 0 L 10 10 L 0 10 Z", bounds: Rect { left: 0.0, top: 0.0, right: 10.0, bottom: 10.0 } } // path abs_transform: Transform { sx: 1.0, kx: 0.0, ky: 0.0, sy: 1.0, tx: 20.0, ty: 0.0 } // note tx: 20.0 here!! // path: Path { segments: "M 0 0 L 10 0 L 10 10 L 0 10 Z", bounds: Rect { left: 0.0, top: 0.0, right: 10.0, bottom: 10.0 } } } ```
```rust // usvg 0.40 fn print_abs_ts(node: &usvg::Node) { if let usvg::Node::Group(g) = node { for child in g.children() { print_abs_ts(child); } } if let usvg::Node::Path(p) = node { println!("path data: {:?}", p.data()); println!("path abs transform: {:?}", node.abs_transform()); } } fn main() { let svg = r##" "##; let tree = usvg::Tree::from_str(&svg, &usvg::Options::default()).unwrap(); for node in tree.root().children() { print_abs_ts(node); } // OUTPUT // // path data: Path { segments: "M 0 0 L 10 0 L 10 10 L 0 10 Z", bounds: Rect { left: 0.0, top: 0.0, right: 10.0, bottom: 10.0 } } // path abs transform: Transform { sx: 1.0, kx: 0.0, ky: 0.0, sy: 1.0, tx: 0.0, ty: 0.0 } // path data: Path { segments: "M 0 0 L 10 0 L 10 10 L 0 10 Z", bounds: Rect { left: 0.0, top: 0.0, right: 10.0, bottom: 10.0 } } // path abs transform: Transform { sx: 1.0, kx: 0.0, ky: 0.0, sy: 1.0, tx: 0.0, ty: 0.0 } // there is no tx: 20.0 here!! } ```
I think you're confusing how SVG works internally. You're trying to map your input 1:1 to debug log you have, but it would not work this way.
I would suggest using usvg
CLI tool to convert your SVG first. This way you would see how usvg/resvg transforms SVG before rendering. This should solve your issues.
I would suggest using usvg CLI tool to convert your SVG first. This way you would see how usvg/resvg transforms SVG before rendering. This should solve your issues.
It is indeed solved because use
s are removed.
It should return the same value as before.
But I still feel a little bit concerned about this. it seems that v0.40
produce a different abs_transform
from v0.37
. It is a bug or it is intended?
Hm... yes, you need node.abs_transform().pre_concat(node.transform())
. From Group::abs_transform
docs:
Contains all ancestors transforms excluding element's transform.
So I guess it did changed. Sorry, there were an absurd amount of changes since 0.37. Hard to track them all.
Also, we mainly test only rendering and resvg renderer doesn't use abs_transform()
internally.
In the end, I think it is a bug. Will take a closer look later.
Thank you for your understanding and patience! I've migrate the code to use transform
only, just like what resvg did. so currently the bug don't block me anymore.
BTW, node.abs_transform().pre_concat(node.transform())
looks like what i'm initially looking for but it seems to be missing in public api. https://docs.rs/usvg/latest/usvg/enum.Node.html. There is no transform
for Node
and Path
, only Group
has this.
I'd also like to express my genuine appreciation for the resvg series project. It's really hard to believe these project are made by a single person! It's clear that a great deal of effort and passion has gone into this, and it does not go unnoticed. Thank you for your hard work; it makes a real difference to many.
Yes, transform
is available only on groups. I've meant: group.abs_transform().pre_concat(group.transform())
.
It's not really about private API. In usvg, only Group
elements can have transforms. Other nodes can't. Hard to explain why without diving deep into SVG internals.
I know that usvg
API is a bit confusing. This is because it's designed mainly for resvg
and is constantly changing.
There are plans on making it a bit nicer, but it's not the main priority. The main goal is still correct rendering.
Thanks you for the kind words. Much appreciated.
Contains all ancestors transforms excluding element’s transform.
That statement was false. abs_transform
does include element's transform.
But there were also a bug in use
removing which got fixed.
The doc of
usvg::Path::abs_transform
:It says that element's transform is excluded. How to get it, so we can get the full absolute of an element?
To make it clear, I make a small function to print all
abs_transform
of all nodes in tree:For this svg(note the
x=30 y=20
part):The output is
I'd like to know how to get
x="30" y="20"
in usvg, because they are required to render a svg.I'm using: