Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to convert the vector path records into SVG path data #284

Open
velara3 opened this issue Mar 16, 2023 · 1 comment
Open

How to convert the vector path records into SVG path data #284

velara3 opened this issue Mar 16, 2023 · 1 comment

Comments

@velara3
Copy link

velara3 commented Mar 16, 2023

i have shapes that I would like to convert to path data.

When I get a reference to the node layer I pass the vector mask to this function:

 function getPathData(data) {
   var disable = data.disable;
   var invert = data.invert;
   var notLink = data.notLink;
   var paths = data.paths;
   var numberOfPaths = paths.length;
   var pathData = "";
   var pathArray = [];
   const typeLetter = ["", "q", "Q", "", "c", "C"]; // this is a guess!
   var pathLength = 0;
   var fill = null;

   for (var i=0; i<numberOfPaths; i++) {
      var segment = paths[i];
      var type = segment.recordType;

      /**
       * 0, 3 is @_readPathRecord
       * 1, 2, 4, 5 then @_readBezierPoint
       * 7 then @_readClipboardRecord
       * 8 then @_readInitialFill
       * 
       * From psdjs/psd/path_record.coffee
       */

      /**
       * 0 - closed subpath length record
       * 1 - closed subpath bezier knot, linked
       * 2 - closed subpath bezier knot, unlinked
       * 3 - open subpath length record
       * 4 - open subpath bezier knot, linked
       * 5 - open subpath bezier knot, unlinked
       * 6 - path fill rule record
       * 7 - clipboard record
       * 8 - initial fill rule record
       */

      switch(type) {
      case 0:
         // Closed subpath length record
         pathLength = segment.numPoints;
         break;
      case 3: 
         // Open subpath length record
         pathLength = segment.numPoints;
         break;
      case 1:
      case 2:
      case 4:
      case 5:
         // Open subpath Bezier knot, unlinked
         pathData = addString(pathData, typeLetter[type] + addString(segment.preceding.horiz, segment.preceding.vert));
         pathData = addString(pathData, addString(segment.leaving.horiz, segment.leaving.vert));
         pathData = addString(pathData, typeLetter[type] + addString(segment.anchor.horiz, segment.anchor.vert));
         break;
      case 6: 
         // Path fill rule record
         pathData += "";
         break;
      case 7:
         // Clipboard record
         pathData += '';
         break;
      case 8:
         // Initial fill rule record
         fill = segment.initialFill; 
         pathData += '';
         break;
      }
   }

   return pathData;
}

function getShapeData(node) {
   var vectorOrigination = node.get("vectorOrigination");
   var isShape = vectorOrigination!=null;

   if (isShape) {
      var vectorMask = node.get("vectorMask")?.export();
      var vectorStroke = node.get("vectorStroke")?.data;
      var vectorStrokeContent = node.get("vectorStrokeContent")?.data;
      var keyDescriptorList = vectorOrigination.data?.keyDescriptorList;
      var keyDescriptor = keyDescriptorList && keyDescriptorList[0];
      
      if (keyDescriptor) {
         var keyOriginType = keyDescriptor.keyOriginType;
         var shapeInfo = new Object();
         shapeInfo.strokeEnabled = vectorStroke.strokeEnabled;
         shapeInfo.strokeWidth = vectorStroke.strokeStyleLineWidth.value;
         shapeInfo.strokeColor = getRGBColor(vectorStroke.strokeStyleContent, vectorStroke.strokeStyleOpacity.value);
         shapeInfo.fillEnabled = vectorStroke.fillEnabled;
         shapeInfo.fillColor = getRGBColor(vectorStrokeContent);
         shapeInfo.pathRecords = vectorMask.paths;
         shapeInfo.pathData = getPathData(vectorMask);
     }
   }

  return shapeInfo;
}

function addString(value, anotherValue, separator = " ") {
   var char = "";
 
   if (value!=null && value!="") {
      value = value + "";
 
      if (anotherValue!=null) {
         anotherValue = anotherValue + "";

         char = value.charAt(value.length-1);

         if (char==separator) {
            value += anotherValue;
         }
         else {
            value += separator + anotherValue;
         }
      }
   }
   else {
      value = "";
      
      if (anotherValue!=null) {
         anotherValue = anotherValue + "";
         value += anotherValue;
      }
   }
   return value;
 }

The path Data string that I'm creating does not work. And it's not surprising because I don't know what each record type relates to what path data command.

Here is some sample trimmed path record data:

[
  {
    "recordType": 6
  },
  {
    "recordType": 8,
    "initialFill": 0
  },
  {
    "recordType": 0,
    "numPoints": 257
  },
  {
    "recordType": 2,
    "linked": false,
    "closed": true,
    "preceding": {
      "vert": 0.14081686735153198,
      "horiz": 0.07748442888259888
    },
    "anchor": {
      "vert": 0.14081686735153198,
      "horiz": 0.0777387022972107
    },
    "leaving": {
      "vert": 0.13936221599578857,
      "horiz": 0.0777667760848999
    }
  },
  {
    "recordType": 2,
    "linked": false,
    "closed": true,
    "preceding": {
      "vert": 0.13929903507232666,
      "horiz": 0.07793217897415161
    },
    "anchor": {
      "vert": 0.1385088562965393,
      "horiz": 0.07837295532226562
    },
    "leaving": {
      "vert": 0.13777965307235718,
      "horiz": 0.07837295532226562
    }
  },
  {
    "recordType": 2,
    "linked": false,
    "closed": true,
    "preceding": {
      "vert": 0.13706856966018677,
      "horiz": 0.07837295532226562
    },
    "anchor": {
      "vert": 0.13632577657699585,
      "horiz": 0.07837295532226562
    },
    "leaving": {
      "vert": 0.1364198923110962,
      "horiz": 0.07855236530303955
    }
  },
  {
    "recordType": 2,
    "linked": false,
    "closed": true,
    "preceding": {
      "vert": 0.13649815320968628,
      "horiz": 0.07873183488845825
    },
    "anchor": {
      "vert": 0.13657790422439575,
      "horiz": 0.07890427112579346
    },
    "leaving": {
      "vert": 0.1359773874282837,
      "horiz": 0.07879406213760376
    }
  },
  {
    "recordType": 2,
    "linked": false,
    "closed": true,
    "preceding": {
      "vert": 0.13536030054092407,
      "horiz": 0.07869088649749756
    },
    "anchor": {
      "vert": 0.1347590684890747,
      "horiz": 0.07858771085739136
    },
    "leaving": {
      "vert": 0.13486969470977783,
      "horiz": 0.07879406213760376
    }
  },
  {
    "recordType": 2,
    "linked": false,
    "closed": true,
    "preceding": {
      "vert": 0.13499760627746582,
      "horiz": 0.07900881767272949
    },
    "anchor": {
      "vert": 0.13512402772903442,
      "horiz": 0.07922220230102539
    },
    "leaving": {
      "vert": 0.1344437599182129,
      "horiz": 0.07920092344284058
    }
  },
  {
    "recordType": 2,
    "linked": false,
    "closed": true,
    "preceding": {
      "vert": 0.1268816590309143,
      "horiz": 0.08006417751312256
    },
    "anchor": {
      "vert": 0.12613815069198608,
      "horiz": 0.08038073778152466
    },
    "leaving": {
      "vert": 0.12613815069198608,
      "horiz": 0.08055287599563599
    }
  },
  {
    "recordType": 2,
    "linked": false,
    "closed": true,
    "preceding": {
      "vert": 0.12613815069198608,
      "horiz": 0.08073228597640991
    },
    "anchor": {
      "vert": 0.12613815069198608,
      "horiz": 0.08091175556182861
    },
    "leaving": {
      "vert": 0.1256791353225708,
      "horiz": 0.0807945728302002
    }
  },
  {
    "recordType": 2,
    "linked": false,
    "closed": true,
    "preceding": {
      "vert": 0.12177199125289917,
      "horiz": 0.08080857992172241
    },
    "anchor": {
      "vert": 0.12177199125289917,
      "horiz": 0.08080857992172241
    },
    "leaving": {
      "vert": 0.12169301509857178,
      "horiz": 0.08107715845108032
    }
  }
]

Related:

@velara3 velara3 changed the title How to convert the path records into path data How to convert the vector shape path records into path data Mar 16, 2023
@velara3 velara3 changed the title How to convert the vector shape path records into path data How to convert the vector path records into SVG path data Mar 16, 2023
@herrstrietzel
Copy link

herrstrietzel commented Mar 20, 2023

Pardon me for being nit picky, but issue posts should be reserved for reporting potential bugs or depicting wrong/misleading/missing parts in the documentation.

This is clearly not the case – the clip path parsing works flawlessly (at least in this case).

You're asking for a "How to" or implementation approach – which should rather be the domain of Q&A platforms like StackOverflow.

I've actually posted a detailed explanation on StackOverflow – probably not a perfect answer/explanation.

But it's not the developers' job to answer these kind of questions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants