web-dev-qa-db-fra.com

Aplatissement des transformations de matrice SVG dans Inkscape

J'ai un fichier SVG clipart gratuit créé à l'origine dans Inkscape auquel je fais des modifications pour l'utiliser dans un jeu JavaScript Windows 8. Il contient de nombreuses instances d'un chemin avec une transformation matricielle appliquée sur un groupe environnant, comme ceci:

<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>

Je souhaite aplatir cette transformation en l'appliquant à l'avance au chemin dans Inkscape, pour réduire le travail du navigateur pendant l'animation. Cependant, lorsque je branche les 6 valeurs de matrice dans les paramètres A B C D E F dans Inkscape et les applique, cela donne au chemin une rotation et une mise à l'échelle complètement différentes de ce que fait le moteur IE10.

J'ai vérifié à plusieurs reprises que les 6 valeurs sont correctement mappées. Qu'est-ce que je fais mal?

EDIT: OK, voici des captures d'écran avant et après IE10 et Inkscape. Pour le cas IE10, le SVG réside directement dans le corps d'un document HTML autrement vide (le rendu est exactement le même dans Firefox). Dans Inkscape, j'ai simplement ouvert le fichier SVG "avant" qui ne contient que l'élément path, sélectionné le chemin et branché les 6 valeurs de transformation de matrice dans Object> Transform> Matrix. Je connais très peu les matrices, je veux juste pouvoir pré-appliquer ces transformations de la même manière que le navigateur, et idéalement pour comprendre pourquoi il y a une différence dans Inkscape. Merci.

IE10 path onlyIE10 path with transformInkscape path onlyInkscape path with transform

39
Tom Hall

Réponse courte

Lorsque vous saisissez les paramètres de la matrice de transformation dans Inkscape, assurez-vous que la case "Modifier la matrice actuelle" est cochée, car si vous appliquez une nouvelle matrice de transformation à un objet, vous multipliez en fait cette nouvelle matrice par la matrice de transformation existante de l'objet, donc assurez-vous de le modifier à la place.
enter image description here

Longue réponse

Comment tout recalculer vous-même.

Essayons d'abord de comprendre un peu les matrices de transformation. Une matrice de transformation est un outil rapide et intelligent pour appliquer des transformations affines (transformation qui préserve les lignes droites) à un vecteur.
Donc, si vous avez un vecteur (disons, coordonnées 2D) et une matrice de transformation, et multipliez les deux ensemble, vous vous retrouverez avec des coordonnées transformées, avec les transformations définies dans la matrice de transformation, appliquées.
transformation matrix
Calcul de x' et y' se fait comme ceci:

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

Ensuite, nous devons comprendre un peu le format svg.
Selon la spécification svg w3c la transformation matrix prend exactement ces 6 paramètres (a, b, c, d, e, f) comme arguments.
Par conséquent, d'après votre exemple,

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

nous avons les paramètres de matrice de transformation suivants:

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

Maintenant, si nous avons l'exemple de coordonnée suivant: x=27, y=-9, nous pouvons le transformer, en utilisant la matrice de transformation précédemment définie comme ceci:

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

Neat, hein? Vous pouvez obtenir plus d'informations ici

Mais ce n'est pas tout. Nous devons également comprendre les données du chemin svg.
Selon la w3c svg path dspecification chaque lettre dans les données de chemin représente une instruction. Et chacune des paires de nombres qui suivent une instruction représente une valeur de coordonnées.

D'après votre exemple, nous avons le chemin suivant:

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

Ici, nous voyons que cet objet chemin utilise une instruction absolue moveto (majuscule [~ # ~] m [~ # ~] ), un parent smooth curveto courbe de Bézier cubique (minuscule s ), une instruction relative lineto (minuscule l ), et un autre parent smooth curveto instruction de courbe de Bézier cubique, suivie d'une instruction closepath (minuscule z ).

M486,313 est traduit en moveto absolu x = 486, y = 313
s27-9,43-29 est un peu plus compliqué à lire car certains comas sont omis car ils ne sont pas nécessaires si le nombre négatif est négatif, donc le signe moins agit comme un coma - de toute façon, cela se traduit par relative lisse bezier curveto x = 27, y = -9, x = 43, y = -29 (un point de destination et un point de contrôle)
Etc.

Alors, comment appliquer et supprimer la matrice de transformation de votre groupe svg? Ainsi:

// 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 Déplacement absolu vers

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

Passer à l'instruction est maintenant M524.589,200.892

S27-9,43-29 - courbure lisse, répétez le même processus pour chaque coordonnée, mais définissez les e et f (paramètres de traduction) à 0, car c'est une instruction relative et non un absolu.
C'est maintenant
s20.025,20.205,45.033,25.680999999999997

l26,4,1,23-22,5
va devenir
l7.934000000000001,25.067999999999998, -20.165,11.085, -14.226, -17.497

s-25-6-48-3
va devenir
s-5.698999999999999, -25.058000000000003, -18.576, -44.337

Et z restera z

Ainsi, le chemin transformé résultant sera:

<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" />

J'espère que cela a du sens pour vous.

56
ArtBIT

Vous pouvez cuire les coordonnées en sélectionnant le chemin puis en utilisant Chemin -> Union (CTRL ++). J'espère que cela t'aides

20
parameciostudio

Coller sur place peut vous aider:

  1. Double-cliquez sur le groupe dans Inkscape, pour l'entrer.
  2. Sélectionner tout le contenu du groupe en appuyant sur Ctrl + A, et copier les avec Ctrl + C.
  3. Double-cliquez à l'extérieur le groupe pour quitter le groupe.
  4. Modifier> Coller sur place (Ctrl + Alt + V) - à ce stade, les transformations de groupe sont appliquées aux objets que vous collez.
  5. Groupe les objets à nouveau (Ctrl + G)
  6. Déplacez le nouveau groupe à la même profondeur que l'original et supprimez le groupe d'origine. (C'est probablement plus facile avec l'éditeur XML, Ctrl + Shift + X.)
15
andraaspar

Suite à la réponse de @andraaspar, vous pouvez également essayer de dissocier (Ctrl-U) et de regrouper à nouveau (Ctrl-G). Ça a marché pour moi.

11
btel

Merci ArtBIT pour toutes les infos! J'ai eu quelques problèmes à ce sujet sur une application PHP, et j'ai écrit une bibliothèque qui manipule les données de police (à partir du fichier SVG) et fait toute sorte de transformation dessus. Toute autre personne intéressée peut l'essayer depuis le GitHub:

https://github.com/kartsims/easysvg

Exemple d'utilisation:

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();

Exemple de manipulation de données 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)
1
kartsims