Menu

Getting accurate height of rendered text

Help
2010-10-06
2012-10-09
  • Saul Willers

    Saul Willers - 2010-10-06

    Hi Nicola,

    The example code suggested in the doc block for getStringHeight() works pretty
    well to get the height of rendered text.
    http://www.tecnick.com/pagefiles/tcpdf/doc/com-tecnick-tcpdf/TCPDF.html#metho
    dgetStringHeight

    However it doesn't allow for character variation, i.e. '123' gives exactly the
    same height as '123g' where the 'g' clearly has a descender which should
    increase the total rendered height.

    I've tried different settings for line height with setCellHeightRatio() but
    nothing seems to be able to reliably get the hight of just the rendered text.

    Am I missing something simple?

    Thanks, Saul

     
  • Nicola Asuni

    Nicola Asuni - 2010-10-06

    The method getStringHeight() return the estimated needed height for print a
    simple text string in Multicell() method and NOT a generic string height.
    A single line height is calculated as: $this->FontSize *
    $this->cell_height_ratio

     
  • Saul Willers

    Saul Willers - 2010-10-06

    Yes, I appreciate that. But I'm not using getStringHeight(). Instead I'm using
    the code from that functions doc block, the one after "Generally, if you want
    to know the exact height for a block of content you can use the following
    alternative technique: ".

    What I'm after is getting the exact height a line of text occupies. E.g. "123"
    takes up less height than "123g" because the "g" has a descender. I need to
    get the exact height, is this possible?

    Thanks, Saul

     
  • Nicola Asuni

    Nicola Asuni - 2010-10-06

    Even using the suggested technique you get the complete line height, because
    the Y position is updated at least by Cell() method.
    If you need to know the font ascent and descent, you can use the
    getFontAscent() and getFontDescent() methods.

    If you upgrade to the latest TCPDF version, check the example n.57 that
    contains a picture with all cell metrics.

     
  • Saul Willers

    Saul Willers - 2010-10-07

    Hi Nicola,

    The tcpdf_cell.png graphic you added to example 57 is excellent. So good I'd
    say it's totally lost hiding at the bottom of the page on example 57. Would be
    good to see that moved to a more prominent place in the documentation.

    I've been using both getFontAscent() and getFontDescent() as well as using the
    FontBBox returned from getFontBuffer() (is there a reason that function is
    protected?). These are great for finding the "outer bounds" of a font. However
    none of them seem to be able to accurately give me the exact height of given
    text rendered by MultiCell().

    Is there any way to totally remove the line height from the final height
    calculation, i.e. just get at the rendered font height?

    Thanks, Saul

     
  • Nicola Asuni

    Nicola Asuni - 2010-10-07

    getFontBuffer() - is there a reason that function is protected?

    Yes, because you should not use it :) This method is designed just for
    internal usage.
    Anyway if you really understand what you are doing and you are not scared
    about the possibility that the next version could broke your existing code,
    then you can use this method on your extended class or even override it.

    none of them seem to be able to accurately give me the exact height of given
    text

    Please note that a font height is a fixed parameter calculated on the maximum
    space taken by all characters. So, you can get the height of a single glyph.

    Is there any way to totally remove the line height from the final height
    calculation

    You can set the line height ratio to 1 using the method setCellHeightRatio(1).
    In this way the calculate line height will be equal to the font height.

     
  • Saul Willers

    Saul Willers - 2010-10-07

    Thanks for the pointers Nicola.

    This method is designed just for internal usage.

    Indeed, I'm already accessing it in my extended class to get at FontBBox
    values.
    Just wondering if it really should be restricted to internal usage: http://
    aperiplus.sourceforge.net/visibility.php

    I've tried changing values to setCellHeightRatio(), however the returned
    height still doesn't vary based on the contents of the text. The goal here is
    to get an exact height for a small (single line) of text, excluding all
    line height. I.e. get the exact height of just the rendered characters.

    Please note that a font height is a fixed parameter calculated on the
    maximum space taken by all characters. So, you can get the height of a single
    glyph.

    I assume that last "can" is a typo and should be "cannot"? If so then that's
    unfortunate and it seems there's currently no way to do what I'm after.

    makefont.php returns the 'cw' (Character Width) for each glyph. Is there any
    possibility it could return the ch (Character Height) for each glyph? That
    would (in theory) enable me to achieve what I'm after?

    Thanks again,
    Saul

     
  • Nicola Asuni

    Nicola Asuni - 2010-10-07

    "you cannot get the height of a single glyph"

    Is there any possibility it could return the ch (Character Height) for each
    glyph? That would (in theory) enable me to achieve what I'm after?

    No, unless you parse the original font file and build your own array of
    heights.

     
  • Saul Willers

    Saul Willers - 2010-10-07

    Ok fair enough. If I was to get this working would you accept a patch for
    makefont.php which added a ch array similar to cw?

     
  • Nicola Asuni

    Nicola Asuni - 2010-10-07

    Probably you are trying to do something in a too complex way. Maybe a simpler
    solution exist.
    Consider also that if you add information to the font, this will became much
    bigger and the library will slow a while.
    Probably you can use a different strategy to achieve your goal.

     
  • Saul Willers

    Saul Willers - 2010-10-07

    Fair point about bloating the font files = library slow down.

    As for a different strategy, I'm all ears! Over many days I've tried
    everything I can think of. The goal is for a single line of text to exactly
    fill a given height, or as close as possible.

    Any alternate methods spring to mind?

    Cheers, Saul

     
  • Nicola Asuni

    Nicola Asuni - 2010-10-07

    OK. A possible solution can be:
    A single character can be divided in three parts (from top to bottom): top =
    font-cap, middle = (font-ascent - font-cap), bottom = font-descent.
    You can build an array where for each char you specify what areas are covered
    (top, middle, bottom).
    Then you can write a function that loops on all characters of a string and
    calculate which parts are covered.
    Once you know this information you can exactly calculate the line height.

    If you like this strategy, please post here your code so I can help you
    further and eventually integrate this on the main class.

     
  • Saul Willers

    Saul Willers - 2010-10-07

    Nice. Interesting work around. That should come close.

    Trouble is that I also need this to work accurately with different fonts.

    Case in point: http://img832.imageshack.us/img832/6201/selection003e.png
    Which show the character "3" rendered in 3 different fonts. All exactly the
    same point size from exactly the same baseline. Goes to show there is real
    variation on the vertical dimensions of each character from font to font.

    So while your solution should work well in most cases the project we're
    working on demands pretty exacting standards across many different fonts.

    I'm beginning to think that implementing ch array will be the only reliable
    method to solve this.

    I will certainly contribute any methods we develop back here, would love to
    see them included in the main class. Or perhaps, due to performance concerns,
    an optional "add on". Is there any precedent for this?

    I'll outline these requirements to our project team and get back to you here.
    It may be that we pursue this, but just at a later stage in the project.

    Many thanks again Nicola,
    ciao, Saul

     
  • Nicola Asuni

    Nicola Asuni - 2010-10-07

    The proposed method works in any font with the same table. You just record if
    a particular caracter fill or not one of the 3 regions, then you use the font
    metrics to calculate the size.

    For example the letter 'f' fills the top an middle position, 'g' fills the
    middle and bottom, 'a' fills only middle.
    Since you know the font ascent, descent and cap from font metrics you can
    easily calculate the string height.
    For the various formulas you can check the existing methods.

     
  • Saul Willers

    Saul Willers - 2010-10-07

    I see what you mean, but I don't think it's right. And that's because the
    vertical space occupied by characters varies per font.

    http://img832.imageshack.us/img832/6201/selection003e.png has "3" in 3 different fonts taking
    up; middle, middle, middle + bottom. So you'd need these stats per font. If
    going to that extent the the ch array seems to be a similar amount of work,
    and should be guaranteed to work as it would hold the exact glyph height.

     
  • Nicola Asuni

    Nicola Asuni - 2010-10-07

    Mmmm. I think that the number '3' must be always (top + middle), otherwise the
    baseline alignment looks weird.
    Anyway, if you want to use "exotic" fonts that are out of general conventions
    you have to look to a different strategy.

     
  • Saul Willers

    Saul Willers - 2010-10-07

    Yep, I'd say the same thing, without the same baseline things look weird!

    However even something like Garamond (a pretty standard font) uses some odd
    baseline alignments, look at the numbers 1-9 bottom right: http://en.wikipedi
    a.org/wiki/File:AdobeGaramondSp.svg

    This is to say nothing of ascenders which vary widely per font as well.

    So yes, we're really after a solution that does take in standard, but also
    "exotic" fonts as accurately as possible.

     

Log in to post a comment.