使用 C# 将 SVG 元素转换为 PNG 文件
SVG element to PNG file with C#
我正在尝试将 SVG 转换为 PNG 文件。我的主要问题不是转换本身(我可以用几行代码来完成),而是我要发送的 SVG 元素居中到得到渲染的 "window" 中。
我使用 SVG 引擎 (https://github.com/vvvv/SVG),我的想法是获取我想要渲染的元素,然后将其重新定位在原点,然后将 svg 文档的宽度和高度设置为 width/height 元素。
这是代码:
var svgDocument = SvgDocument.Open(filename);
var el =(SvgVisualElement) svgDocument.GetElementById("MyId");
// set in the origin
el.Transforms.Add(new SvgTranslate(-el.Bounds.X, -el.Bounds.Y));
// set doc dimensions
svgDocument.Width = el.Bounds.Width;
svgDocument.Height = el.Bounds.Height;
bitmap.Save("PNGFile", ImageFormat.Png);
不幸的是,它不是那样工作的。
这是一个不起作用的 svg 示例(它很长,所以我删除了相关部分):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="70.125473"
height="190.98564"
id="svg6678"
version="1.1">
<g id="MyId">
<g
transform="translate(-2375.7448,475.88408)"
id="Texture:door_single_rocks_gear">
<path
id="path9179-8-2-8-71-4-2-7"
d="..." style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#5b3636;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.53245842;marker:none;enable-background:accumulate" />
<path
id="path9179-8-2-8-71-4-6"
d="..." style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#815656;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.53245842;marker:none;enable-background:accumulate" />
<path
id="path4080-5-2"
d="..."
style="fill:#866262;fill-opacity:1;stroke:none" />
<path
id="path7662-1-1-4-9"
d="..."
style="fill:#5b3636;fill-opacity:1;stroke:none" />
<path
id="path7662-1-1-4-5-5"
d="..."
style="fill:#5b3636;fill-opacity:1;stroke:none" />
</g>
<g
id="Texture:door_single_rocks"
inkscape:label="#g5299"
inkscape:export-filename="C:\Users\stefano.liboni\Dropbox\AndroidStudio\AsteroidRage\scenes_source\door_single_rocks.png"
inkscape:export-xdpi="199.88191"
inkscape:export-ydpi="199.88191">
<path style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#5b3636;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
d="..."
id="rect4972-3-8-9" />
<path
id="rect4972-9"
d="..." style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#815656;fill-opacity:1;fill-rule:nonzero;stroke:#5b3636;stroke-width:1.0026859;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
style="fill:#5b3636;fill-opacity:1;stroke:none"
d="..."
id="path7662-1-1-4-5-5-0" />
<path
style="fill:#5b3636;fill-opacity:1;stroke:none"
d="..."
id="path7662-1-1-4-5-5-03-9" />
<path
style="fill:#5b3636;fill-opacity:1;stroke:none"
d="..."
id="path7662-1-1-4-5-5-03" />
</g>
<g
id="AnimatedTexture:door_single_rocks_led"
inkscape:label="#g5295">
<path
id="path9095-7"
d="..."
style="fill:#9486ff;fill-opacity:1;stroke:#000000;stroke-width:1.07693017;stroke-opacity:1" />
<path
id="path9095-7-5-1"
d="..."
style="fill:#9486ff;fill-opacity:1;stroke:#000000;stroke-width:1.07693017;stroke-opacity:1" />
</g>
</g>
</svg>
如您所见,有一个 g 元素 MyId 充满了其他 g 元素和一些路径。我添加了它在 inkscape.
中渲染的图像
在我的代码中获得元素的边界(即左下角的那个)后,我得到:
{X = -1502.69763 Y = 668.7914 宽度 = 2514.11938 高度 = 870.0564}
这似乎是错误的,因为该元素只有 141 像素的宽度和 395 像素的高度...
如果我 运行 该文件的代码输出是:
所以PNG有很多未使用的space,png的y,width和height都是错误的。正确的是:
svgDocument.X = 0;
svgDocument.Y = -476;
svgDocument.Width = 141;
svgDocument.Height = 395;
知道我做错了什么吗?
注意:我知道 inkscape 会做对(我以前用过它),但至少 3 年来有一个错误,他们懒得解决,这会阻止 inkscape 无声地 运行如果您在命令行中指定 "verb" 模式。所以联合起来很痛苦,因为它打开每个文件 UI 并需要 3-4 秒才能完成...
我没有找到是否有该库的文档。我查看了源代码,但主要是我能解释的是 SVG 部分。也许引擎提供了更简单的方法。
transform
根 svg 元素上的属性是合法的,但在您想要完成的内容的上下文中,它们比帮助更令人困惑,因为还有其他导致转换的属性,但是被写以不同的形式。
<svg>
元素提供的属性可以更直接地满足您的需求:
忽略最外层 svg 元素上的 x
和 y
属性。
width
和 height
描述图像渲染到的 output 维度。所以它们应该反映最终的 "window" 维度。如果 SVG 最初的尺寸不适合您的 "window",请更改它们。
viewBox
描述应该渲染 internal SVG viewport(根元素的坐标系)的哪一部分。这 不是 所选元素 returns 的 SVGVisualElement.Bounds
结构。 (相对于元素本身坐标系的值,但不包括所有父元素转换)我在库中找不到任何函数可以为您提供所需的值。
preserveAspectRatio
描述了渲染部分如何适合输出 window。例如,默认的XMidYMid meet
,意思是:用最大尺寸调整viewBox区域的大小,使其刚好适合width/height,不会向任何方向溢出,并将其定位在中心。
虽然我不知道如何从库中获取所需的边界框值,但其他程序可以毫无问题地提供它们:
inkscape -I MyID
在命令行
- 在浏览器中通过 Javascript
document.getElementById("MyId").getBBox()
在 ccprog 的评论推动下,我发现 UI 是由 inkscape 开放的,因为我在 运行.
的同一命令中还做了其他事情
实际上 运行ning inkscape 为:
MyFile.svg --export-id=ElementIdToRender --export-id-only --export-dpi=200 --export-png="TargetFile"
做这份工作。
仍然理解为什么 SVG 库为 g 元素提供奇怪的数字作为边界,这些元素包含一个或多个具有变换属性集的子元素,但目前我可以继续。
发送
我正在尝试将 SVG 转换为 PNG 文件。我的主要问题不是转换本身(我可以用几行代码来完成),而是我要发送的 SVG 元素居中到得到渲染的 "window" 中。
我使用 SVG 引擎 (https://github.com/vvvv/SVG),我的想法是获取我想要渲染的元素,然后将其重新定位在原点,然后将 svg 文档的宽度和高度设置为 width/height 元素。 这是代码:
var svgDocument = SvgDocument.Open(filename);
var el =(SvgVisualElement) svgDocument.GetElementById("MyId");
// set in the origin
el.Transforms.Add(new SvgTranslate(-el.Bounds.X, -el.Bounds.Y));
// set doc dimensions
svgDocument.Width = el.Bounds.Width;
svgDocument.Height = el.Bounds.Height;
bitmap.Save("PNGFile", ImageFormat.Png);
不幸的是,它不是那样工作的。 这是一个不起作用的 svg 示例(它很长,所以我删除了相关部分):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="70.125473"
height="190.98564"
id="svg6678"
version="1.1">
<g id="MyId">
<g
transform="translate(-2375.7448,475.88408)"
id="Texture:door_single_rocks_gear">
<path
id="path9179-8-2-8-71-4-2-7"
d="..." style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#5b3636;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.53245842;marker:none;enable-background:accumulate" />
<path
id="path9179-8-2-8-71-4-6"
d="..." style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#815656;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.53245842;marker:none;enable-background:accumulate" />
<path
id="path4080-5-2"
d="..."
style="fill:#866262;fill-opacity:1;stroke:none" />
<path
id="path7662-1-1-4-9"
d="..."
style="fill:#5b3636;fill-opacity:1;stroke:none" />
<path
id="path7662-1-1-4-5-5"
d="..."
style="fill:#5b3636;fill-opacity:1;stroke:none" />
</g>
<g
id="Texture:door_single_rocks"
inkscape:label="#g5299"
inkscape:export-filename="C:\Users\stefano.liboni\Dropbox\AndroidStudio\AsteroidRage\scenes_source\door_single_rocks.png"
inkscape:export-xdpi="199.88191"
inkscape:export-ydpi="199.88191">
<path style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#5b3636;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
d="..."
id="rect4972-3-8-9" />
<path
id="rect4972-9"
d="..." style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#815656;fill-opacity:1;fill-rule:nonzero;stroke:#5b3636;stroke-width:1.0026859;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" />
<path
style="fill:#5b3636;fill-opacity:1;stroke:none"
d="..."
id="path7662-1-1-4-5-5-0" />
<path
style="fill:#5b3636;fill-opacity:1;stroke:none"
d="..."
id="path7662-1-1-4-5-5-03-9" />
<path
style="fill:#5b3636;fill-opacity:1;stroke:none"
d="..."
id="path7662-1-1-4-5-5-03" />
</g>
<g
id="AnimatedTexture:door_single_rocks_led"
inkscape:label="#g5295">
<path
id="path9095-7"
d="..."
style="fill:#9486ff;fill-opacity:1;stroke:#000000;stroke-width:1.07693017;stroke-opacity:1" />
<path
id="path9095-7-5-1"
d="..."
style="fill:#9486ff;fill-opacity:1;stroke:#000000;stroke-width:1.07693017;stroke-opacity:1" />
</g>
</g>
</svg>
如您所见,有一个 g 元素 MyId 充满了其他 g 元素和一些路径。我添加了它在 inkscape
在我的代码中获得元素的边界(即左下角的那个)后,我得到: {X = -1502.69763 Y = 668.7914 宽度 = 2514.11938 高度 = 870.0564}
这似乎是错误的,因为该元素只有 141 像素的宽度和 395 像素的高度...
如果我 运行 该文件的代码输出是:
所以PNG有很多未使用的space,png的y,width和height都是错误的。正确的是:
svgDocument.X = 0;
svgDocument.Y = -476;
svgDocument.Width = 141;
svgDocument.Height = 395;
知道我做错了什么吗?
注意:我知道 inkscape 会做对(我以前用过它),但至少 3 年来有一个错误,他们懒得解决,这会阻止 inkscape 无声地 运行如果您在命令行中指定 "verb" 模式。所以联合起来很痛苦,因为它打开每个文件 UI 并需要 3-4 秒才能完成...
我没有找到是否有该库的文档。我查看了源代码,但主要是我能解释的是 SVG 部分。也许引擎提供了更简单的方法。
transform
根 svg 元素上的属性是合法的,但在您想要完成的内容的上下文中,它们比帮助更令人困惑,因为还有其他导致转换的属性,但是被写以不同的形式。
<svg>
元素提供的属性可以更直接地满足您的需求:
-
忽略最外层 svg 元素上的
x
和y
属性。width
和height
描述图像渲染到的 output 维度。所以它们应该反映最终的 "window" 维度。如果 SVG 最初的尺寸不适合您的 "window",请更改它们。viewBox
描述应该渲染 internal SVG viewport(根元素的坐标系)的哪一部分。这 不是 所选元素 returns 的SVGVisualElement.Bounds
结构。 (相对于元素本身坐标系的值,但不包括所有父元素转换)我在库中找不到任何函数可以为您提供所需的值。preserveAspectRatio
描述了渲染部分如何适合输出 window。例如,默认的XMidYMid meet
,意思是:用最大尺寸调整viewBox区域的大小,使其刚好适合width/height,不会向任何方向溢出,并将其定位在中心。
虽然我不知道如何从库中获取所需的边界框值,但其他程序可以毫无问题地提供它们:
inkscape -I MyID
在命令行- 在浏览器中通过 Javascript
document.getElementById("MyId").getBBox()
在 ccprog 的评论推动下,我发现 UI 是由 inkscape 开放的,因为我在 运行.
的同一命令中还做了其他事情实际上 运行ning inkscape 为:
MyFile.svg --export-id=ElementIdToRender --export-id-only --export-dpi=200 --export-png="TargetFile"
做这份工作。
仍然理解为什么 SVG 库为 g 元素提供奇怪的数字作为边界,这些元素包含一个或多个具有变换属性集的子元素,但目前我可以继续。 发送