Flattening SVG matrix transforms in Inkscape

前端 未结 5 1404
眼角桃花
眼角桃花 2020-12-07 22:56

I have a free clip art SVG file originally created in Inkscape which I\'m making modifications to for use in a Windows 8 JavaScript game. It contains numerous instances of a

相关标签:
5条回答
  • 2020-12-07 23:06

    Paste In Place can help you:

    1. Double click the group in Inkscape, to enter it.
    2. Select all the contents of the group by pressing Ctrl+A, and copy them with Ctrl+C.
    3. Double click outside the group to leave the group.
    4. Edit > Paste In Place (Ctrl+Alt+V) – at this point, group transformations are applied to the obects you paste.
    5. Group the objects again (Ctrl+G)
    6. Move the new group to the same depth as the original, and delete the original group. (This is probably easier with the XML editor, Ctrl+Shift+X.)
    0 讨论(0)
  • 2020-12-07 23:08

    Following the answer of @andraaspar, you can also try ungrouping (Ctrl-U) and grouping again (Ctrl-G). It worked for me.

    0 讨论(0)
  • 2020-12-07 23:08

    Thanks ArtBIT for all the info ! I had some issues about this on a PHP app, and wrote a library that manipulates font data (from SVG file) and does any sort of transformation on it. Anyone else interested may give it a try from the GitHub :

    https://github.com/kartsims/easysvg

    Usage example :

    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 data manipulation example :

    $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)
    
    0 讨论(0)
  • 2020-12-07 23:13

    Short answer

    When typing the transformation matrix params in Inkscape, make sure you have "Edit current matrix" checked, since if you apply a new transformation matrix to an object, you're actually multiplying this new matrix with the existing transformation matrix of the object, so make sure you edit it instead.
    enter image description here

    Long Answer

    How to recalculate everything yourself.

    First let us try and understand the transformation matrices a bit. A transformation matrix is a quick and clever tool for applying affine transformations ( transformation which preserves straight lines) to a vector.
    So, if you have a vector (say, 2d coordinates) and a transformation matrix, and multiply the two together, you will end up with transformed coordinates, with the transformations defined in the transformation matrix, applied.
    transformation matrix
    Calculating x' and y' is done like so:

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

    Next, we need to understand the svg format a bit.
    According to the w3c svg spec the matrix transform takes exactly those 6 parameters (a,b,c,d,e,f) as arguments.
    Therefore, from your example,

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

    we have the following transformation matrix params:

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

    Now, if we have the following example coordinate: x=27, y=-9, we can transform it, by using the previously defined transformation matrix like this:

    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, huh? You can get more info here

    But that is not all. We also need to understand svg path data.
    According to the w3c svg path dspecification each letter in the path data represents an instruction. And each of the number pairs that follow an instruction represent a coordinate value.

    From your example, we have the following path:

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

    Here we see that this path object uses one absolute moveto instruction (uppercase M), a relative smooth curveto cubic Bézier curve (lowercase s), a relative lineto instruction (lowercase l), and another relative smooth curveto cubic Bézier curve instruction, followed by a closepath instruction (lowercase z).

    M486,313 is translated to absolute moveto x=486, y=313
    s27-9,43-29 is a bit more complicated to read because some comas are omitted because they're not needed if the negative number is negative, so the minus sign acts as a coma - anyways, it translates to relative smooth bezier curveto x=27, y=-9, x=43, y=-29 (one destination point and one control point)
    And so on.

    So, how do we apply and remove the transformation matrix from your svg group? Like so:

    // 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 Absolute move to

    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
    

    Move to instruction is now M524.589,200.892

    S27-9,43-29 - smooth curveto, repeat the same process for each coordinate, but set the e and f (translation parameters) to 0, since it's a relative instruction not an absolute.
    It is now
    s20.025,20.205,45.033,25.680999999999997

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

    s-25-6-48-3
    will become
    s-5.698999999999999,-25.058000000000003,-18.576,-44.337

    And z will remain z

    So the resulting transformed path will be:

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

    I hope this makes sense to you.

    0 讨论(0)
  • 2020-12-07 23:25

    You can bake the coords selecting the path then using Path -> Union (CTRL++). Hope this helps

    0 讨论(0)
提交回复
热议问题