Skip to main content
Participating Frequently
April 12, 2024
Question

Extracting SVG Coordinates

  • April 12, 2024
  • 1 reply
  • 1666 views

I am needing to extract SVG coordinates for a script that I am running in After Effects. I have created an icon in illustrator, saved it as an SVG and pulled this string from it:

["M0,64.31V30.34L32.36,0l32.37,30.37v33.95H0Z"]

The script I am using is requires that the SVG coordinates be in this format:
["21.32 9.44 26.33 8.84 22.26 11.25 24.93 16.40 33.72 16.40 38.68 11.99 34 10.06 33.59 12.99 30 11.25 32.02 8.82 36.36 8.84 47 13 36 21 21 21 13 13 20 4 38 2 47 13 44.10 12.62 37.13 4.10 21.04 5.92 16.91 11.32"]

Is there anyway to get a string of coordinates from an SVG that will follow the format above?

Here is a link to the script: https://github.com/adamplouff/scriptui-battlestyle/tree/master
This topic has been closed for replies.

1 reply

jduncan
Community Expert
Community Expert
April 12, 2024

So, I had a few minutes and this seemed like fun. PLEASE NOTE, there is no error checking and I only implemented the command in the raw string you provided (so you will have to implement the rest of the commands to cover all situations).

 

You can learn a lot about how the SVG commands work here https://www.nan.fyi/svg-paths/lines.

 

I'm sure there are better ways to do this, but I tried to be as simple and explicit in the short amount of time I had to mess with this.

 

Hope it helps!

 

// SVG COMMANDS
//   M = moveto (move from one point to another point)
//   L = lineto (create a line)
//   H = horizontal lineto (create a horizontal line)
//   V = vertical lineto (create a vertical line)
//   C = curveto (create a curve)
//   S = smooth curveto (create a smooth curve)
//   Q = quadratic Bézier curve (create a quadratic Bézier curve)
//   T = smooth quadratic Bézier curveto (create a smooth quadratic Bézier curve)
//   A = elliptical Arc (create a elliptical arc)
//   Z = closepath (close the path)
// Note: All of the commands above can also be expressed in lower case. Upper case means absolutely positioned, lower case means relatively positioned.

function cleanAddition(n1, n2) {
  return (n1 * 100 + n2 * 100) / 100;
}

function parseParams(s) {
  var params = [];
  var splitParams = s.split(",");
  var cur;
  for (var p = 0; p < splitParams.length; p++) {
    cur = parseFloat(splitParams[p]);
    if (!isNaN(cur)) {
      params.push(cur);
    }
  }
  return params;
}

function execSVGCommand(pos, command, params) {
  x = pos[0];
  y = pos[1];

  // moveto
  if (command.toUpperCase() == "M") {
    if (command == "M") {
      x = params[0];
      y = params[1];
    } else {
      x = cleanAddition(x, params[0]);
      y = cleanAddition(y, params[1]);
    }
  }

  // vertical lineto
  if (command.toUpperCase() == "V") {
    if (command == "V") {
      x = 0;
      y = params[0];
    } else {
      y = cleanAddition(y, params[0]);
    }
  }

  // lineto
  if (command.toUpperCase() == "L") {
    if (command == "L") {
      x = params[0];
      y = params[1];
    } else {
      x = cleanAddition(x, params[0]);
      y = cleanAddition(y, params[1]);
    }
  }

  // horizontal lineto
  if (command.toUpperCase() == "H") {
    if (command == "H") {
      x = params[0];
    } else {
      y = cleanAddition(y, params[0]);
    }
  }

  return [x, y];
}

function parseSVGPath(s) {
  var pathCommands = [];
  var command;
  var params;

  for (var i = 0; i < s.length; i++) {
    if (/[a-zA-Z]/.test(s[i])) {
      command = s[i];
      params = "";
      for (var n = i + 1; n < s.length; n++) {
        if (/[a-zA-Z]/.test(s[n])) {
          i = n - 1;
          break;
        }
        params += s[n];
      }
      pathCommands.push({ command: command, params: parseParams(params) });
    }
  }

  return pathCommands;
}

// the raw svg commands you extracted
var rawPath = "M0,64.31V30.34L32.36,0l32.37,30.37v33.95H0Z";

// parse out the commands and their params
var parsedPath = parseSVGPath(rawPath);

// perform the commands to determine each point along the path
var points = [];
var coords = [];
var pos = [0, 0];
var command;
var params;
for (var i = 0; i < parsedPath.length; i++) {
  command = parsedPath[i]["command"];
  params = parsedPath[i]["params"];
  if (command == "Z") {
    // check for clospath command
    pos = points[0];
  } else {
    pos = execSVGCommand(pos, command, params);
  }
  points.push(pos);
  coords.push(pos[0]);
  coords.push(pos[1]);
}

alert("Points (array)\n" + points);
alert('Points (formatted For Ae)\n["' + coords.join(" ") + '"]');

 

m1b
Community Expert
Community Expert
April 13, 2024

Hi @jduncan, I was recently drawn in to this challenge from a different direction, and wrote a basic SVG parser to draw illustrator DOM objects from svg data string. I found it was fun to do and it sounds like you did too. So we are both weirdos! 🙂

- Mark

 

Note: where I come from, being a "weirdo" is just fine. If it's a bad term where you come from, my apologies and I will edit.

jduncan
Community Expert
Community Expert
April 14, 2024

Haha, I'm definitely a weirdo! Your implementation looks way better thought out than mine btw. Cheers!