Сглаживание матриц SVG в Inkscape

У меня есть бесплатный SVG файл, созданный в Inkscape, который я вношу изменения для использования в игре с 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 матричных значений к параметрам A B C D E F в Inkscape и применяю их, он дает пути совершенно другого вращения и масштабирования к тому, что делает движок IE10.

Я проверил много раз, что у меня правильно отображены 6 значений. Что я делаю неправильно?

EDIT: ОК, вот до и после скриншотов из IE10 и Inkscape. Для случая IE10 SVG находится непосредственно внутри тела иначе написанного HTML-документа (рендеринг точно такой же в Firefox). В Inkscape я просто открыл SVG файл "до", который содержит только элемент пути, выбрал путь и подключил 6 значений матричного преобразования в Object > Transform > Matrix. Я очень мало знаю о матрицах, я просто хочу иметь возможность предварительно применять эти преобразования так же, как это делает браузер, и в идеале понять, почему в Inkscape есть разница. Спасибо.

IE10 path onlyIE10 path with transformInkscape path onlyInkscape path with transform

Ответ 1

Короткий ответ

При вводе параметров матрицы преобразования в Inkscape убедитесь, что вы проверили "Редактировать текущую матрицу", поскольку, если вы применяете новую матрицу преобразования к объекту, вы фактически умножаете эту новую матрицу на существующую матрицу преобразования объект, поэтому убедитесь, что вы его отредактируете. enter image description here

Длинный ответ

Как пересчитать все самостоятельно.

Сначала попробуем немного понять матрицы преобразования. Матрица преобразования является быстрым и умным инструментом для применения аффинных преобразований (преобразования, которые сохраняют прямые) к вектору. Итак, если у вас есть вектор (скажем, 2d-координаты) и матрица преобразования, и умножьте два вместе, вы получите преобразованные координаты с преобразованиями, определенными в матрице преобразования. transformation matrix
Вычисление x' и y' выполняется следующим образом:

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

Далее нам нужно немного понять формат svg.
В соответствии с w3c svg spec преобразование 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), a относительная инструкция lineto (строчная строка l) и другая относительная инструкция smooth curveto кубическая кривая Безье, за которой следует инструкция closepath (строчная z).

M486,313 переводится в абсолютное moveto x = 486, y = 313
s27-9,43-29 немного сложнее читать, потому что некоторые комы опущены, потому что они не нужны, если отрицательное число отрицательно, поэтому знак минуса действует как кома - в любом случае он переводится в относительный гладкий bezier curveto 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 - гладкое curveto, повторите тот же процесс для каждой координаты, но установите e и 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" />

Я надеюсь, что это имеет смысл для вас.

Ответ 2

Вы можете испечь координаты, выбирающие путь, затем используя Path → Union (CTRL ++). Надеюсь, что это поможет

Ответ 3

Вставить на место может помочь вам:

  • Дважды щелкните по группе в Inkscape, чтобы ввести ее.
  • Выберите все содержимое группы, нажав Ctrl + A и скопируйте их с помощью Ctrl + C.
  • Дважды нажмите группу, чтобы покинуть группу.
  • Изменить > Вставить на место (Ctrl + Alt + V) - в этот момент групповые преобразования применяются к вложенным объектам.
  • Группировать объекты снова (Ctrl + G)
  • Переместите новую группу на ту же глубину, что и оригинал, и удалите исходную группу. (Это, вероятно, проще с 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)