Get height of wrapping text

edited May 2016 in How To...

I have been breaking my brain over something that should be very simple: getting the height of wrapping text. It seems that processing has no function to calculate the height of wrapped text? I found an old workaround, dating from 2006 and 2007 (!), but this doesn't include a working example. http://wiki.processing.org/index.php?title=Word_wrap_text Does anyone have a better method to calculate the height of wrapping text?

Answers

  • edited March 2014 Answer ✓

    The following code is an old snippet I coded in Processing 1.5.1, but it still works in Processing 2.X:

    ///////////////////////////////////////////////////////////
    // Variable definitions ///////////////////////////////////
    ///////////////////////////////////////////////////////////
    String testString = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.";
    
    
    ///////////////////////////////////////////////////////////
    // Init ///////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
    void setup() {
        size(600, 600);
        background(#000000);
    
        textFont(loadFont("ArialMT-20.vlw"), 20);
        textLeading(textAscent()+4);
    }
    
    
    ///////////////////////////////////////////////////////////
    // Render /////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
    void draw() {
    
        // Render background
        background(#000000);
    
        // Format test string
        String displayText = createLineBreaks(testString, mouseX-20);
    
        // Render text
        fill(#ffffff); stroke(#ffffff);
        text(testString, 20, 20, mouseX-20);
        line(20, 0, 20, height);
        line(mouseX, 0, mouseX, height);
        line(20, 20+textHeight(displayText), mouseX, 20+textHeight(displayText));
    
    }
    
    
    ///////////////////////////////////////////////////////////
    // Format string //////////////////////////////////////////
    ///////////////////////////////////////////////////////////
    public String createLineBreaks(String str, float maxWidth) {
    
        // Remove unnecessary spaces
        // and add (unix) linebreak characters if line length exceeds maxWidth
        StringBuilder strBuffer = new StringBuilder(str.length());
        boolean firstSpace = false;
        int lastSpace = -1, iB = 0;
        float currentWidth = 0, wordWidth = 0;
        for(int i = 0, n = str.length(); i < n; i++) {
            char c = str.charAt(i);
            if(c == ' ') { // If this character is a space
                if(firstSpace) { // If this space is the first space in a row
                    if(currentWidth > maxWidth && lastSpace > -1) {
                        strBuffer.setCharAt(lastSpace, (char)10);
                        currentWidth -= wordWidth;
                    }
                    currentWidth += textWidth(c);
                    wordWidth = currentWidth;
                    lastSpace = iB;
                    strBuffer.append(c);
                    firstSpace = false;
                    iB++;
                }
            } else { // If character is no space
                currentWidth += textWidth(c);
                strBuffer.append(c);
                firstSpace = true;
                iB++;
            }
        }
        if(currentWidth > maxWidth && lastSpace > -1) // If last line still exceeds maxWidth
            strBuffer.setCharAt(lastSpace, (char)10);
    
        // Return string
        return strBuffer.toString();
    
    }
    
    
    ///////////////////////////////////////////////////////////
    // Render textbox with specified maximum width ////////////
    ///////////////////////////////////////////////////////////
    public void text(String str, float x, float y, float maxWidth) {
        text(createLineBreaks(str, maxWidth), x, y+textAscent());
    }
    
    
    
    ///////////////////////////////////////////////////////////
    // Return text leading value //////////////////////////////
    ///////////////////////////////////////////////////////////
    public float textLeading() {
        return g.textLeading;
    }
    
    
    ///////////////////////////////////////////////////////////
    // Return text leading value //////////////////////////////
    ///////////////////////////////////////////////////////////
    public float textHeight(String str) {
    
        // Count (unix) linebreaks
        int linebreaks = 0;
        for(int i = 0, n = str.length(); i < n; i++)
            if(str.charAt(i) == (char)10)
                linebreaks++;
    
        // Calculate & return height
        if(linebreaks == 0)
            return textAscent() + textDescent();
        else
            return linebreaks * textLeading() + textAscent() + textDescent();
    
    }
    

    Just use createLineBreaks() to get the wrapped text and use textHeight() to get it's height.

    Or simply use Daniel Shiffman's function like the following (not tested):

    float textHeight = wordWrap(someText, someWidth).size() * textLeading();
    
  • Thanks! Using your code and Daniel Shiffman's I was able to create a wrapping textfield with a measurable height :-) I have to say it's still a slightly convoluted way for something that should be simple. I hope Processing will add better support for text in the future!

  • edited March 2014

    Yub, and it's pretty slow performance wise - try to re-calculate the text height as few times as possible.

    Would be great if Processing's text(str, x1, y1, x2, y2) would simply return a float[]/PVector containing the resulting text box dimensions. :)

Sign In or Register to comment.