Is it really not possible to determine the precise height of a text?

edited December 2016 in Programming Questions

I want to be able to draw the exact bounding box of a text. The width is not a problem, I can use the textWidth() function and give it the string I'm rendering, but when it comes to its height, I'm clueless. Yes, functions textAscent() and textDescent() are available and their sum gives me the maximum height of the font in general, but what I need is the height of a particular string or a character which is potentially smaller in height..

Is there a workaround that'll give me what I want??

Cheers

Answers

  • There is a way to find the height of a glyph (character image). If textAscent() or font size isn't good enough you can loop over all characters and find the maximum value.

    String s = "test";
    PFont font = createFont("Arial", 36);
    textFont(font);
    int max = 0;
    for (char c : s.toCharArray())
    {
      PFont.Glyph g = font.getGlyph(c);   //the magic
      if (g.height > max) max = g.height;
    }
    
    background(0);
    fill(255, 0, 0);
    rect(10, 10, textWidth(s), max);
    fill(0);
    text(s, 10, 10+max);
    
  • But I'd stick with the normal textSize, as this method is a bit long.

  • @colouredmirrorball

    Thank you so much, this is exactly what I needed!

    @Lord_of_the_Galaxy

    I'm sorry, but I think you misunderstood what I needed, textSize() is used to, well, set the text size, and what I need is the precise width/height of any character I want.

  • What I meant was that whatever value you use in textSize() is the maximum height of that font as a whole.

  • True, but that's not at all what I need. I need to be able to calculate the exact bounding box of any possible character.

  • Work around would be to draw on an invisible PGraphics and detect the max size with get()

  • @Chrisir -- interesting workaround.

    Will that give different / more precise values than the PFont.Glyph.height approach suggested by @colouredmirrorball ? Or are they two ways of achieving the same thing?

  • No idea

    We need to know more about the goal

    Are you trying to make each letter clickable or just words?

  • edited December 2016

    Hey, maybe I wasn't clear enough, but colouredmirrorball's revelation of the PFont.Glyph class is exactly what I needed and I also think it's the "right" method that gives precise results - I consider my question answered.

    Anyway, I'm generating some random dataset for training a neural network used for OCR, and for each generated character I need to know exactly where it is and what is its bounding box, and PFont.Glyph's attributes offer exactly what I need.

    @Chrisir It's not about making the characters/words clickable, it's just about obtaining each character's bounding box. And while I'm sure the PGraphics method could work, I think the suggested PFont.Glyph aproach would be faster if anything, and it offers what I need.

  • There is a problem with this approach - try using the letter "p" or "y" in your text and you'll notice that the bounding box will end up above the required position because text is a bit below the given y position.

  • And I found a fix. Try this code:

    PFont font;
    
    void setup(){
      size(640, 360);
      font = createFont("Arial", 48);
      background(0);
      fill(255);
      textFont(font);
    }
    
    void draw(){
    }
    
    void keyPressed(){
      PFont.Glyph glyph = font.getGlyph(key);
      println(glyph.height);
      println(glyph.width);
      println((char)glyph.value);
      println(glyph.index);
      println(glyph.topExtent);
      println(glyph.leftExtent);
      //println(glyph.height);
    
      background(0);
      fill(0, 0, 255);
      text(key, 50, 100);
      int l = glyph.leftExtent;
      int t = glyph.topExtent;
      int h = glyph.height;
      int w = glyph.width;
      noFill();
      stroke(255, 255, 0);
      rect(50 + l, 100 - t, w, h);
    }
    
  • edited February 2017

    Thank you @Lord_of_the_Galaxy, I ran into that problem and fortunately found the solution (like yours) looking at the javadocs.

Sign In or Register to comment.