10

I'm currently working on a JavaScript project that uses the HTML5 canvas as a rendering target. In order for my code to play nicely with the (rigidly specified) interfaces I've been provided, I need to be able to take a font and extract the ascent and descent heights of that font. This will allow clients to more accurately position the text. I'm aware that I can change where the text draws by setting the textBaseline attribute, but I actually need the numeric values describing these different heights. Is there a simple way to do this? If not, is there a (hopefully lightweight) library that can handle it for me? Most of the proposed solutions I've found are heavyweight font rendering libraries, which seems like massive overkill for this problem.

6
  • Mozillas Bespin tried to solve that problem and finally run into argument which ended with the conclusion canvas was and will never be designed for text editors. So either rely on 'm' having same height and width or use the source of Bespin or the pixel test method described below or measure an off div with same text/font or any other unreliable approximation. Sorry, don't like disillusion, too. But are you sure you chose the right horse for this path? Commented May 29, 2011 at 23:10
  • I'm currently working on an implementation of the JVM in JavaScript and am using the canvas as a rendering target. I need to implement the Java font libraries, which is why I need these precise values. I'm thinking that I'm going to go with Simon's answer and just fake up the implementation by writing offscreen and pixel-scraping the results back. :-( Commented May 29, 2011 at 23:53
  • I hope, you have considered font smoothing.... Commented May 30, 2011 at 0:05
  • 1
    @templatetypedef Is it too late to answer this? I have the solution. ctx.measureText("text").width. I think that's right. I'll double check it if you still need it. Commented Aug 19, 2011 at 1:13
  • 2
    @Ryan Amos- I'm aware of this solution, but it only computes the width of the text, not the height, font ascent, or font descent, which are the values that I actually needed. Thanks, though! Commented Aug 19, 2011 at 1:15

4 Answers 4

4

This article on HTML5 Typographic Metrics discusses the problem and a part solution using CSS - although the integer rounding of offsetTop etc is a problem (potentially can use getBoundingClientRect() to get proper floating point values for some browsers).

Sign up to request clarification or add additional context in comments.

Comments

4

The short answer is that there is no built in way and you are sort-of on your own.

Because of this, most people simply estimate them. Some people pre-calculate all the values, which isn't too much work provided you are using only a few fonts.

The third way is to make a canvas in memory and print some letters (say, a Q and an O) and programatically attempt to determine the ascent and descent using per-pixel collision. It's a pain and can be slow depending on the number of fonts and how accurate you want to be, but it is the most accurate way of going about it if you do not want to pre-compute the values.

Comments

1

Just as a reference here: The width of the text can be measured with:

ctx.measureText(txt).width

http://www.w3schools.com/tags/canvas_measuretext.asp

Comments

1

For both the width and height, you could try this:

let txt="AVA BC efg hij IÍ";
let measure=ctx.measureText(txt);
let width=measure.width;
let fullHeight=measure.fontBoundingBoxAscent+measure.fontBoundingBoxDescent;
let ascentHeight=measure.fontBoundingBoxAscent;

The width value handles all of the possible kerning between letters. (ie. AVA) The ascentHeight would measure from the baseline of where the text is drawn to the height of the tallest capital letter. And the fullHeight can cover from the highest letter to lowercase "g" and "j".

1 Comment

Wow, things have changed a lot since I asked this question thirteen years ago! Back then the only data in a TextMetrics was the width. I am glad to see that has evolved in the intervening decade!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.