【问题标题】:SVG element to PNG file with C#使用 C# 将 SVG 元素转换为 PNG 文件
【发布时间】:2018-02-14 17:48:47
【问题描述】:

我正在尝试将 SVG 转换为 PNG 文件。我的主要问题不是转换本身(我可以用几行代码完成),而是我想要发送到渲染的“窗口”中的 SVG 元素的居中。

我使用 SVG 引擎 (https://github.com/vvvv/SVG),我的想法是获取要渲染的元素,然后将其重新定位在原点,然后将 svg 文档的宽度和高度设置为元素的宽度/高度。 这是代码:

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有很多未使用的空间,png的y,宽度和高度都是错误的。正确的应该是:

svgDocument.X = 0;
svgDocument.Y = -476;
svgDocument.Width = 141;
svgDocument.Height = 395;

知道我做错了什么吗?

注意:我知道 inkscape 会做对(我曾经使用它),但是至少有 3 年以来他们没有费心去解决一个错误,如果你指定“动词”,它会阻止 inkscape 在静默模式下运行" 在命令行中。所以取消它是一件痛苦的事情,因为对于每个文件,它都会打开 UI 并需要 3-4 秒才能完成......

【问题讨论】:

  • ------------------------------------------ - - - - - - - - - - - - - - - - - - - 更新 - - - - - - ----------------------------------------- 正如我认为的那样,它与我要渲染的元素内的 g 元素的 transfrom 属性。如果我去掉所有的变换属性,它就可以正常工作,不仅适用于这个例子,而且适用于更复杂的几何图形。如何考虑这些转换?
  • 您能详细解释一下您遇到的inkscape CLI 问题吗?我正在成功地使用它来完成您描述的或多或少相同的任务。

标签: c# svg bounding-box inkscape


【解决方案1】:

我还没有找到该库是否有文档。我查看了源代码,但主要是我能解释的是 SVG 部分。也许引擎自己提供了更简单的方法。

transform 根 svg 元素上的属性是合法的,但在你想要完成的上下文中,它们比有用更令人困惑,因为还有其他属性会导致转换,但以不同的形式编写.

&lt;svg&gt; 元素提供的属性可以更直接地匹配您想要完成的任务:

  • 忽略最外层 svg 元素上的xy 属性。

  • widthheight 描述了图像渲染到的输出 维度。所以它们应该反映最终的“窗口”尺寸。如果 SVG 最初的尺寸不适合您的“窗口”,请更改它们。

  • viewBox 描述应该渲染 internal SVG 视口(根元素的坐标系)的哪一部分。这 不是 所选元素的 SVGVisualElement.Bounds 结构返回的内容。 (相对于元素本身坐标系的值,但不包括所有父元素转换​​)我在库中找不到任何可以为您提供所需值的函数。

  • preserveAspectRatio 描述了渲染部分如何适应输出窗口。例如XMidYMid meet,这是默认值,意思是:将viewBox区域调整为最大尺寸,使其恰好适合宽度/高度,不会在任何方向溢出,并将其定位在中心。

虽然我不知道如何从库中获取所需的边界框值,但其他程序可以毫无问题地提供它们:

  • inkscape -I MyID 在命令行中
  • 在浏览器中通过 Javascript document.getElementById("MyId").getBBox()

【讨论】:

  • Tnx 寻求帮助。我已经更改了 svg 文档的宽度和高度,但是使用了我要渲染的元素的 Bounds 属性,这又似乎是错误的,因为它给出了太高的值......摆脱所有变换一切正常,并且 Bounds 给出正确的价值观。 SVG库中应该有一个错误...
  • 您可以通过使用不同的软件对其进行测试来验证 Bounds 的值。直接在现代浏览器中打开 .svg,按 打开开发者工具,在集成控制台中输入document.getElementById("MyId").getBBox()。结果应该是一个与该元素的 Bounds 属性相匹配的对象。
  • 再次阅读库源代码后,我现在确定 Bounds 没有提供所需的值 - 这不是错误,但缺少关于该属性是什么的文档。好吧,一个错误:Bounds doesn't account for child transforms,但即使解决了这个问题也无法满足您的需求。
  • 我认为这是我的问题......对孩子的改造。 Tnx 指出来。
【解决方案2】:

在 ccprog 的评论的推动下,我发现 UI 是由 inkscape 开放的,因为我在运行的同一命令中也在做其他事情。

实际运行 inkscape 为:

MyFile.svg --export-id=ElementIdToRender --export-id-only --export-dpi=200 --export-png="TargetFile"

完成这项工作。

仍然不明白为什么 SVG 库会为包含一个或多个具有变换属性集的子元素的 g 元素提供奇怪的数字作为边界,但目前我可以继续。 天呐

【讨论】:

    猜你喜欢
    • 2010-09-08
    • 2019-10-17
    • 2015-10-04
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    • 2018-05-05
    • 2016-06-17
    • 2021-08-04
    相关资源
    最近更新 更多