【问题标题】:Flattening SVG matrix transforms in Inkscape在 Inkscape 中展平 SVG 矩阵变换
【发布时间】:2013-01-19 00:58:42
【问题描述】:

我有一个最初在 Inkscape 中创建的免费剪贴画 SVG 文件,我正在对其进行修改,以便在 Windows 8 JavaScript 游戏中使用。它包含许多路径实例,其中矩阵变换应用于周围组,如下所示:

<g transform="matrix(0.443,0.896,-0.896,0.443,589.739,-373.223)">
    <path d="M486,313s27-9,43-29l26,4,1,23-22,5s-25-6-48-3z" />
</g>

我想通过提前将变换应用到 Inkscape 中的路径来展平该变换,以减少动画期间的浏览器工作。但是,当我将 6 个矩阵值插入 Inkscape 中的 A B C D E F 参数并应用它时,它会为路径提供与 IE10 引擎完全不同的旋转和缩放。

我已经检查了很多次,我已经正确映射了 6 个值。我做错了什么?

编辑:好的,这里是 IE10 和 Inkscape 之前和之后的屏幕截图。对于 IE10 案例,SVG 直接位于一个空的 HTML 文档的正文中(在 Firefox 中呈现完全相同)。在 Inkscape 中,我只是打开了仅包含路径元素的“之前”SVG 文件,选择了路径,并将 6 个矩阵变换值插入到对象 > 变换 > 矩阵中。 我对矩阵知之甚少,我只是希望能够以与浏览器相同的方式预先应用这些转换,并且理想地了解为什么 Inkscape 会有所不同。谢谢。

【问题讨论】:

标签: matrix svg transform inkscape


【解决方案1】:

简答

在 Inkscape 中键入变换矩阵参数时,请确保选中“编辑当前矩阵”,因为如果将新的变换矩阵应用于对象,实际上是将该新矩阵与现有的变换矩阵相乘对象,因此请确保改为编辑它。

长答案

如何自己重新计算所有内容。

首先让我们试着理解一下转换矩阵。 变换矩阵是一种快速而巧妙的工具,可将仿射变换(保留直线的变换)应用于向量。
因此,如果您有一个向量(例如,二维坐标)和一个变换矩阵,并将两者相乘,您将得到变换后的坐标,并应用变换矩阵中定义的变换。
计算x'y' 是这样完成的:

x' = a*x + c*y + e 
y' = b*x + d*y + f

接下来,我们需要了解一下svg格式。
根据w3c svg specmatrix 转换恰好将这 6 个参数 (a,b,c,d,e,f) 作为参数。
因此,从你的例子来看,

<g transform="matrix(0.443,0.896,-0.896,0.443,589.739,-373.223)">

我们有以下变换矩阵参数:

a=0.443
b=0.896
c=-0.896
d=0.443
e=589.739
f=-373.223

现在,如果我们有以下示例坐标:x=27, y=-9,我们可以使用之前定义的变换矩阵来变换它,如下所示:

x' = a*x + c*y + e 
x' = 0.443*27 + -0.896*-9 + 589.739
x' = 609.764

y' = b*x + d*y + f
y' = 0.896*27 + 0.443*-9 -373.223
y' = −353.018

整洁,对吧?您可以获取更多信息here

但这还不是全部。我们还需要了解 svg 路径数据。
根据w3c svg path dspecification,路径数据中的每个字母代表一条指令。指令后面的每个数字对代表一个坐标值。

从您的示例中,我们有以下路径:

<path d="M486,313s27-9,43-29l26,4,1,23-22,5s-25-6-48-3z" />

这里我们看到这个路径对象使用了一个绝对的moveto指令(大写M),一个相对的smooth curveto三次贝塞尔曲线(小写s),一个相对 lineto 指令(小写 l),另一个相对 smooth curveto 三次贝塞尔曲线指令,后跟 closepath 指令(小写 z)。

M486,313 被翻译为 absolute moveto x=486, y=313
s27-9,43-29 读起来有点复杂,因为省略了一些逗号,因为如果负数是负数,所以减号相当于一个昏迷 - 无论如何,它转换为 相对平滑的贝塞尔曲线 x=27, y=-9, x=43, y=-29(一个目的地点和一个控制点)
以此类推。

那么,我们如何从您的 svg 组中应用和删除转换矩阵?像这样:

// we read the transformation matrix params
// <g transform="matrix(0.443,0.896,-0.896,0.443,589.739,-373.223)">
a=0.443
b=0.896
c=-0.896
d=0.443
e=589.739
f=-373.223

// we read the path data, and transform each instruction    
// <path d="M486,313s27-9,43-29l26,4,1,23-22,5s-25-6-48-3z" />

M486,313绝对移动到

x' = a*x + c*y + e = a*486 + c*313 + e = 524.589
y' = b*x + d*y + f = b*486 + d*313 + f = 200.892

移动到指令现在是 M524.589,200.892

S27-9,43-29 - 平滑曲线,对每个坐标重复相同的过程,但将 ef(平移参数)设置为 0,因为它是相对的指令不是绝对的。
现在是
s20.025,20.205,45.033,25.680999999999997

l26,4,1,23-22,5
将变为
l7.934000000000001,25.067999999999998,-20.165,11.085,-14.226,-17.497

s-25-6-48-3
将变为
s-5.698999999999999,-25.058000000000003,-18.576,-44.337

z 将保持 z

所以转换后的路径将是:

<path d="M524.589,200.892s20.025,20.205,45.033,25.680999999999997l7.934000000000001,25.067999999999998,-20.165,11.085,-14.226,-17.497s-5.698999999999999,-25.058000000000003,-18.576,-44.337z" />

我希望这对你有意义。

【讨论】:

  • 这是一个很好的答案,谢谢!我需要一段时间来消化手动应用转换的过程。同时,当我在 Inkscape 中设置“编辑当前矩阵”标志时,它现在确实给出了正确的视觉结果 - 但是,当我保存 SVG 文件(作为标准 Inkscape 或优化)时,它与转换一起保存为单独的属性而不是应用于路径值。我在首选项中将“商店转换”设置为优化。我如何让它崩溃转换成路径?谢谢!
  • @TomHall 确保取消组合对象(对象->取消组合或 )并保存为优化的 .svg
  • 但是我作为测试操作的 SVG 文件只有一个直接位于 SVG 节点内部的路径节点(我的问题中的路径)。所以过程是:我打开它,应用转换并勾选编辑当前矩阵并将存储转换设置为优化,然后尝试取消组合,然后保存为优化的 SVG。但它可以像这样添加转换: 不好意思,我做错了什么?
  • 请注意,如果您希望最终外观相同,则通常不能将转换从元素转换到其数据中(即使是&lt;path&gt;)。 skew 的存在尤其会以一种仅用路径命令无法表示的方式非均匀地改变笔画的外观。
  • 这是我见过的对 svg 矩阵的简短解释。这对我帮助很大
【解决方案2】:

您可以选择路径然后使用 Path -> Union (CTRL++) 烘焙坐标。 希望这会有所帮助

【讨论】:

  • 感谢您提供快速简单的解决方案
  • 注意:如果它没有关闭,这将改变路径。
【解决方案3】:

原地粘贴可以帮助您:

  1. 在 Inkscape 中双击组,进入。
  2. 按Ctrl+A全选组的内容,然后按Ctrl+C复制
  3. 在群组外双击退出群组。
  4. Edit > Paste In Place (Ctrl+Alt+V) – 此时,组转换将应用于您粘贴的对象。
  5. 再次分组对象 (Ctrl+G)
  6. 将新组移动到与原始组相同的深度,然后删除原始组。 (使用 XML 编辑器 Ctrl+Shift+X 可能更容易。)

【讨论】:

    【解决方案4】:

    按照@andraaspar 的回答,您也可以尝试取消分组(Ctrl-U)并再次分组(Ctrl-G)。它对我有用。

    【讨论】:

      【解决方案5】:

      感谢 ArtBIT 提供的所有信息!我在一个 PHP 应用程序上遇到了一些问题,并编写了一个库来操作字体数据(来自 SVG 文件)并对其进行任何类型的转换。任何有兴趣的人都可以从 GitHub 尝试一下:

      https://github.com/kartsims/easysvg

      使用示例:

      require 'easySVG.php';
      $svg = new EasySVG();
      $svg->setFont("paris-bold-webfont.svg", 100, "#000000");
      $svg->addText("Simple text display");
      $svg->addAttribute("width", "800px");
      $svg->addAttribute("height", "100px");
      echo $svg->asXML();
      

      SVG 数据操作示例:

      $def = 'YOUR SVG DEFINITION HERE';
      $easySVG = new EasySVG();
      // rotate by 40°
      $rotated_def = $easySVG->defRotate($def, 40)
      // rotate by 40° with center at (200,100)
      $rotated_def2 = $easySVG->defRotate($def, 40, 200, 100)
      // scale transform : width*4
      $scaled_def = $easySVG->defScale($def, 4)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-07
        • 1970-01-01
        • 1970-01-01
        • 2021-03-24
        • 2014-02-10
        相关资源
        最近更新 更多