Search code examples
javascriptpaperjsopentype

Convert paper.js path into an opentype.js path


I have a path in paper.js witch describes a letterform. I got Path by loading a font whith opentype.js's function path.toSVG(); than I load it to paper.js by .importSVG();

Now I do some manipulations with paper.js and then want it back as a downloadable font file. So my question is, is there an easy way to get it back from paper.js to opentype.js?

Edit: Okay I am asuming there is no easy way. So i tried to convert the path manually with js:

for(var i=0; i<fragments.children.length; i++) {

  var glyphName = fragments.children[i].name;

  if (glyphName.indexOf('0x') > -1) {
    var unicode = String.fromCharCode(parseInt(glyphName, 16));
    glyphName = 'uni' + glyphName.charCodeAt(0);
  } else {
    var unicode = glyphName.charCodeAt(0);
  }

  var w = 0;
  var glyphPath = new opentype.Path();

  //Going through the array with the segments of the paper.js Path
  for(var i2 = 0; i2 < fragments.children[i].segments.length; i2++) {

    // handle In
    var x1 = fragments.children[i].segments[i2].handleIn.x;
    var y1 = fragments.children[i].segments[i2].handleIn.y;

    // handle Out
    var x2 = fragments.children[i].segments[i2].handleOut.x;
    var y2 = fragments.children[i].segments[i2].handleOut.y;

    // Point
    var x = fragments.children[i].segments[i2].point.x;
    var y = fragments.children[i].segments[i2].point.y;

    if (i2 === 0) {
       // if its the first segment use move to
       glyphPath.moveTo(x, y);
    } else if(x1==0 && y1==0 && x2 == 0 && y2 == 0) {
       // if there is no curve use line to
       glyphPath.lineTo(x, y);
    } else {
      // use curve if its a curve
      glyphPath.curveTo(x1+x,y1+y, x2+x,y2+y, x,y,);
    }

    if(i2+1 == fragments.children[i].segments.length) {
      glyphPath.close();
    }

    w = Math.max(w, x);
  }


 var glyph = new opentype.Glyph({
    name: fragments.children[i].name,
    unicode: unicode,
    advanceWidth: (w + 1),
    path: glyphPath
 });
}

This gets me an opentype font file to download. However, if i open the font in a Font Viewer the whole Form is upside down and the handles are wrong. The positions of them seem right but somehow the wrong handles are in the position where another one should be...they seem to be switched. I can't figure out what I am missing..

This is how it should look

This is how it looks..


Solution

  • How the problem was solved:
    As mentioned in the comment I saw that there were no straight lines even in fragments which should have straight lines. So i checked the coordinates and realised that there were straight lines (paths with handle x1/y2 and x2/y2 all on coordinate 0/0) if i just push them one ahead.

    For example:

          x        y        x1       y1        x2         y2
    1:  148.29   92.125     0         0       -1.25     -3.5
    2:  140       85      3.93      1.084      0          0
    3:   139.99  74.16      0         0       12.95      2.02
    4:  159.55    92.1     -1.238    -8.283    0         0
    
    

    So i had to change the for loop to actually get the handles of the last point mixed with the ones from the actual point.

    So in this example nr. 1 and nr. 3 would get x1: 0, y1: 0 // x2: 0, y2: 0

    In my for loop i take x1/y1 from the last segment:

    // handle In
    var x1 = fragmentPathObj.segments[i2-1].handleOut.x * letterScale;
    var y1 = fragmentPathObj.segments[i2-1].handleOut.y*-1 * letterScale;
    // handle Out
    var x2 = fragmentPathObj.segments[i2].handleIn.x * letterScale;
    var y2 = fragmentPathObj.segments[i2].handleIn.y*-1 * letterScale;
    

    If i do this i can check for straight lines with:

    if(x1==0 && y1==0 && x2 == 0 && y2 == 0) {
       glyphTempPath.lineTo(x, y);
    }
    

    and draw the curves when there are handles:

    var lastX = fragmentPathObj.segments[i2-1].point.x * letterScale  - letterPosCorrectionX;
    var lastY = fragmentPathObj.segments[i2-1].point.y*-1 * letterScale  - letterPosCorrectionY;
    
    glyphTempPath.curveTo(x1+lastX, y1+lastY, x2+x, y2+y, x,y); 
    

    lastX/lastY: Since x1/y1 is coming from the last segment, i need to calculate the position for the handles also with the x/y of the last point.

    letter Scale: is used for the scaling of the letter and is calculated by dividing the glyph's advanceWidth by the scaledAdvanceWith

    y*-1 : is used to solve the upside down problem.

    letterPosCorrectionX and letterPosCorrectionY; are corrections for the position (so they are moved to the correct position in the font.)

    Maybe this can help someone save some time :)