43

我有一个最初在 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 中的 ABCDEF 参数并应用它时,它会为路径提供与 IE10 引擎完全不同的旋转和缩放。

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

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

仅 IE10 路径 带有变换的 IE10 路径 仅 Inkscape 路径 带有变换的 Inkscape 路径

4

5 回答 5

59

简短的回答

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

长答案

如何自己重新计算一切。

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

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

接下来,我们需要稍微了解一下svg格式。
根据w3c svg 规范matrix转换恰好将这 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

整齐吧?你可以在这里获得更多信息

但这还不是全部。我们还需要了解 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转换为绝对 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 - 平滑曲线,对每个坐标重复相同的过程,但将eand f(平移参数)设置为 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" />

我希望这对你有意义。

于 2013-02-27T13:50:21.783 回答
21

您可以选择路径然后使用路径 -> 联合 (CTRL++) 烘焙坐标。希望这可以帮助

于 2014-03-05T17:35:22.803 回答
21

就地粘贴可以帮助您:

  1. 双击Inkscape 中的组,进入它。
  2. 按 Ctrl+A选择组的所有内容,然后使用 Ctrl+C复制它们。
  3. 在群组外双击退出群组。
  4. 编辑 >就地粘贴(Ctrl+Alt+V) – 此时,组转换将应用于您粘贴的对象。
  5. 再次对对象进行分组(Ctrl+G)
  6. 将新组移动到与原始组相同的深度,并删除原始组。(使用 XML 编辑器 Ctrl+Shift+X 可能更容易。)
于 2014-03-25T08:41:02.103 回答
14

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

于 2015-05-11T20:37:52.020 回答
1

感谢 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)
于 2014-04-21T13:13:38.927 回答