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 know the baseline and x value for font.getPath() ? #277

Closed
microSoftware opened this issue Apr 7, 2017 · 14 comments
Closed

How to know the baseline and x value for font.getPath() ? #277

microSoftware opened this issue Apr 7, 2017 · 14 comments

Comments

@microSoftware
Copy link

microSoftware commented Apr 7, 2017

Hello, this question have already been asked but the answer given didn't work :
var baseline = (font.ascender / font.unitsPerEm * fontSize);
So since it's been a while maybe now there is a solution for it.

Expected Behavior

When I use font.getPath('text', 0,0,40) => the text will be cut on the top or the bottom, or the right...
And I would like to know the value of x and y relatively to the font and text. Or to make it simple, i would like the text to not be cut.

Steps to Reproduce (for bugs)

I made a small repo to visualize the text generated

  1. git clone https://github.com/microSoftware/display-font.git
  2. npm install
  3. node opentype.js (or nodemon opentype.js if you want to watch for modif)
  4. modify the words to see which one work and don't work
  5. Go on http://localhost:8900 to see the result

Thank you

@microSoftware
Copy link
Author

Is there people maintaining this repo ?

@axkibe
Copy link
Contributor

axkibe commented Apr 18, 2017

Honestly, I don't really understand your actual question/problem and debugging your code example is time-costly.

Can you try and write a little more clearly, what you actual issue is?

@fdb
Copy link
Contributor

fdb commented Apr 19, 2017

font.getPath draws the text with 0,0 being the baseline.

So, given a function hline that looks like this:

function hline(y) {
    ctx.beginPath();
    ctx.moveTo(-9999, Math.round(y)-0.5);
    ctx.lineTo(9999, Math.round(y)-0.5);
    ctx.stroke();
}

You can see the relationship between baseline, ascender and descender here:
this code:

// Translate the canvas 150 pixels down.
ctx.translate(0, 150);
// Draw the baseline.
hline(0);

// Calculate / draw ascender and descender.
var fontSize = 64;
var fontScale = 1 / font.unitsPerEm * fontSize;
// Note that ascender / descender are bottom-up, so we need to flip (negate) them.
var topY = -(font.ascender * fontScale);
var bottomY = -(font.descender * fontScale);
ctx.strokeStyle = '#66f';
hline(topY);
hline(bottomY);

// Draw the text at 0,0 (baseline).
var path = font.getPath('The quick brown fox jumps over the lazy dog', 0, 0, fontSize);
path.draw(ctx);

Will draw the text like this, with ascender/descender in blue:

screen shot 2017-04-19 at 14 35 28

Working example in JSFiddle

@fdb
Copy link
Contributor

fdb commented Apr 19, 2017

Since this is the expected behaviour, I'm closing this issue. Feel free to comment if something is still unclear.

@fdb fdb closed this as completed Apr 19, 2017
@microSoftware
Copy link
Author

@axkibe Actually it's the same question than this one. #110

@fdb Thank you for answer. This solution work on the browser side or with Node-Dom because you need the context of the canvas. But the problem for me is that I use OpenType on node and speed is really important. That's why I don't use Node-Dom (it take 1-2s for each getPath call)

Do you see my problem ?

@axkibe
Copy link
Contributor

axkibe commented Apr 20, 2017

Sorry, I still don't get it.

So I guess the actual issue is, you want to position text by its upper left corner?

@axkibe
Copy link
Contributor

axkibe commented Apr 20, 2017

And you don't neet a canvas context for getPath().

@fdb
Copy link
Contributor

fdb commented Apr 20, 2017

I also don't really see why you would need node-dom to render to SVG, for example. All you need is the bit of math that I showed above.

If you want a tight bounding box of the path, that's not something that OpenType.js currently provides. See #272 for more details.

@axkibe
Copy link
Contributor

axkibe commented Apr 20, 2017

Actually as far as I get it, getBoundingBox() returns a tight box. What opentype doesn't support is this returning general bbox that is large enough for any Glyph.

For pixel exactness note that x1/x2/y1/y2 of the BoundingBox are likely not integer values, that is what I believe your issue with "but there is always pixel off".

Usually what I do is taking Math.floor() of x1/y1 and Math.ceil of x2/y2 to have an integer bounding box that is large enough. But I position text on its baseline, which is IMO also the most sane thing to do.

If you want x1/y1 to be on an integer value, you'll have to translate (move) the path by that fraction. Of course x1 and y1 and x2 and y2 to be integral and tight is something I'd say is almost impossible except you have a crazy complicated font hinting program used in your font.

@fdb
Copy link
Contributor

fdb commented Apr 20, 2017

Axel, it would make sense to add that to the core, so that there's a "best practice" approach for getting the bounding box.

Reading #272, that's also what's discussed there. I'm fan of adding a font.getBbox(text, x, y, fontSize) API call similar to getPath().

@microSoftware
Copy link
Author

Thank you for your help 🙂

I've drawn 3 lines:
The green line is 0:0
The blue line is the ascender
The red line is the descender

font.getPath(word, 0, 0, fontSize) display this :

screen shot 2017-04-20 at 19 29 57

font.getPath(word, 0, 60, fontSize) display this :
screen shot 2017-04-20 at 19 31 26

If I use 0,0 for getPath(). The text is going to be cut off. And the ascender line is cut off.

So what I'm looking for is the y of getPath knowing the font size, ascender, descender, font.
Or any solution that make the text not being cut off.

I hope it make sense.

You can check out the code here : https://github.com/microSoftware/display-font/blob/master/opentype.js

@fdb I know it works with canvas using path.draw(ctx). But I can't make it work without using a canvas.

@axkibe
Copy link
Contributor

axkibe commented Apr 20, 2017

Use path.getBoundingBox()

Then y1 of that is what you seek.

But note that 'X' is for example in most fonts taller than 'o', so both letters would be positioned to the top if you use it like that.

@microSoftware
Copy link
Author

After thinking, what I'm gonna do is to use getPath 0,0 and then move the path relatively to the (-)ascender.
Because everything over 0,0 is hidden. Now I think about it. It looks so obvious. So much trouble for that :/
@axkibe @fdb Thank you so much for your help. I can move on now.

@axkibe
Copy link
Contributor

axkibe commented Apr 20, 2017

Or you getPath(0, -ascender) right away.

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

3 participants