我需要编写一些C#代码,以编程方式对任何SVG文件进行变换。
此选项适用于SVG编辑器,如Affinity Designer(〜$ 40 / Mac)或Inkscape(FOSS):
但是你如何以编程方式执行此操作?即使是好的SVG c# libraries也没有提供这样做的方法。
在SO上有很多讨论(即here,here,here和here)。在那些建议一些工具,但没有人给出代码(除了一些对我没用的javascript片段,因为它使用浏览器API来获取转换的坐标)。
我需要在C#代码中执行此操作,因为要操纵svg元素,我需要这些元素独立于父变换,包括椭圆弧,渐变,文本和tspan元素。
编辑澄清: 我不需要转换元素。我只需要在最深的子节点中存在转换矩阵,所以我不再需要考虑父母了。为此,我需要在单个矩阵中连接所有父矩阵,并将其作为单个转换属性分配给svg元素。我不一定需要转换路径或弧,例如将椭圆转换为路径,或重新采样位图。我只需要能够为每个元素计算一个矩阵变换,它自己作为变换属性分配给它,而不是每次都要考虑所有父组变换。
答案 0 :(得分:0)
这是我的问题的初步答案。但它仍然存在一些元素的问题(带有剪辑路径,蒙版或滤镜属性的元素,或者使用网址或defs,在展平后似乎已经破坏了坐标)。感谢任何进一步的帮助和改进。
public void FlattenNodeRecursive(XElement item) {
var children_elements = item.Elements();
if ( IsSVGElem(item, "g") &&
HasAttr(item,"transform") &&
!item.IsEmpty &&
item.Elements().Any((XElement inner) => { return IsSVGElem(inner, "path") || IsSVGElem(inner, "text") || IsSVGElem(inner, "g"); }) &&
item.Elements().Any((XElement inner) => { return !IsSVGElem(inner, "tspan"); })
) {
XAttribute parent_attribute = item.Attribute("transform");
foreach (var inner in children_elements) {
if (HasAttr(inner, "transform")) {
inner.Attribute("transform").SetValue(ConcatenateTransforms((parent_attribute.Value.Trim() + " " + inner.Attribute("transform").Value.Trim())).Trim());
} else {
XAttribute attribute = new XAttribute("transform", parent_attribute.Value.Trim());
inner.Add(attribute);
}
}
parent_attribute.Remove();
}
foreach(XElement xelem in children_elements){
if(xelem.Elements() != null) {
FlattenNodeRecursive(xelem);
}
}
}
注意:我没有发布HasAttr方法或ConcatenateTransforms方法源代码,因为它们非常简单,但如果有人需要,我会发布它们。