StringHeight not accurate?

It seems that with each new line in a string, Graphics.StringHeight becomes more inaccurate.
Several lines later, StringHeight is cutting off the bottom half of letters.
Is there a reason for this? Is it the font (System), or OS X?

I’d prefer not to have to manage each line in a loop just to get an accurate height reading.

Here’s a screenshot 12 lines down. The cyan line is my debug line set at the StringHeight.

[quote=255958:@Tim Parnell]It seems that with each new line in a string, Graphics.StringHeight becomes more inaccurate.
Several lines later, StringHeight is cutting off the bottom half of letters.
Is there a reason for this? Is it the font (System), or OS X?

I’d prefer not to have to manage each line in a loop just to get an accurate height reading.

Here’s a screenshot 12 lines down. The cyan line is my debug line set at the StringHeight.
[/quote]

It may have to do with line spacing. Normally that is coded into the font, but I noticed often that Xojo adds something. I can’t unfortunately locate the thread, but I had found a way to check the actual like eight somewhere, by drawstring two lines of underscore, and measure the distance by scanning with pixel to see the actual distance.

Maybe you can use something like that to find the true lineheight.

As far as I understand …
DrawString uses one API that doesn’t tell us the height
StringHeight uses a different API that does
And they behave slightly differently and include / exclude different things
Not sure if there is a single consistent API we can use that will draw & measure using the same scheme where they both include interline leading etc etc etc
And whether using a single API would suddenly “break” projects in fun ways as measurements would just change

Me to as the IDE does a LOT of this :slight_smile:

Use TextHeight to got the distance between baselines. StringHeight will be accurate until the last line and then not if there are no descenders on that line.

<https://xojo.com/issue/42786>

How I worked around it for another app; I used countfields( string, endOfLine ) and stuffed the result into a variable at layout time, then used the variable at drawing time.

For the IDE there are spots where “the right thing to do” is split the string into characters & then concatenate things back together to simulate what iOS does or what web browsers do

Tim, it would help if you’d move this to the OSX subtopic as I believe this is specific to OSX and not a general issue.

Also, I’ve managed to deal with this, e.g. in iClip. Not sure how, though. Either I used CGText or other declared calls, or I used not StringHeight but another property that gives me the textheigt. If you don’t find a solution contact me directly and I’ll look up my code. Oh, actually, reading some more comments, I think I’ve done what others suggested: Figure out the number of lines and then multiple that by the TextHeight. But you say you don’t want to do that. Sorry, no other ideas then.

It was a preference on implementation. I ended up going that route after the advice here.
I will Windows test the drawing code later today to be sure it’s safe on both.

Moved to OS X channel in light of this being a Mac specific issue.
Thanks to all for your advice and help.

Sorry, but I do not see how StringHeight and line spacing being different is a Mac OS X specific issue…

Thomas, would you please explain why this would not happen on PC ?

Before you decided apparently out of the blue that it was an OS X issue, never in the discussion anything indicated the PC would not be similarly affected. AFAIK the issue encountered by Tim exists on all three platforms.

Michel, check the feedback case Sam linked.
Screenshots and example project show the behavior only under OS X.

I just did some playing around… and WIndows does seem to be more accurate…
And OSX the variance seems to be based on not only the font, but the font size… it seemed the larger the size, the more accurate it appeared. Not saying it was, just that it appeared visually to be so

  Dim s As String
  Dim x As Integer
  Dim y As Integer
  Dim i As Integer
  g.textsize=30
  g.drawrect 0,0,g.Width,g.Height
  s="Abc^abc^XYZ^xyz"
  s=ReplaceAll(s,"^",EndOfLine)
  For i=0 To 5
    x=10+(i*50)
    y=50
    g.drawstring s,x,y
    //
    y=y-g.TextAscent
    g.drawrect x,y,20,g.StringHeight(s,g.width)
    s=s+EndOfLine+Str(i)+"Xyz"
  Next i

Indeed StringHeight looks adequate under Windows.

The fact that it gets more and more precise with the size could be due to a quantum effect.

One pixel represents a huge percentage in a 12 points font, so rounding error may result in a worse delta.

I played a bit with my method of scanning pixels between two underscore. For ten lines of System 0 which I believe to be the default for graphics, I get 141 for StringHeight, while my method returns 150.

If you use MBS Plugin, did you simply try NSGraphicsMBS.boundingRectWithSize function?
or NSGraphicsMBS.sizeWithAttributes?
http://www.monkeybreadsoftware.net/class-nsgraphicsmbs.shtml

We also have a lot of CoreText functions for more text rendering:
http://www.monkeybreadsoftware.net/pluginpart-coretext.shtml

I followed this thread with interest, since I have never been able to find a perfect formula to draw several lines with the same inter-line spacing.
In my particular case, each line (row) is made up of two strings: if both strings do not wrap, then spacing is all right; but when one of the two strings wraps into several lines, then the next line in the loop gets a different value.
Taking into account what has been said above, I tried this code. Could somebody point me in the right direction? Thanks.
By the way, changing font and size, proportions are not well kept.

dim strH1, strH2 as Integer
dim defaultH as Integer = g.StringHeight(“Help”,20)
dim gap as Integer = g.textsize / 2
dim incr as Integer = 120
//startFirstStr and startSecondStr are the coordinates where to start drawing each string
//lenFirstString and lenSecondString are the max lengths allowed

for k as Integer to s.ubound
dim ss() as String = Split(s(k), chr(9))
g.DrawString ss(0),startFirstStr,incr,lenFirstString
strH1 = g.StringHeight(ss(0),lenFirstString)
//is the string wrapping? If so, how many lines?
strH1 = g.TextHeight * (strH1/defaultH)

g.DrawString ss(1),startSecondStr,incr,lenSecondStr
strH2 = g.StringHeight(ss(1),lenSecondStr)
strH2 = g.TextHeight * (strH2/defaultH)

if strH1 >= strH2 then
  incr = incr + strH1
  if strH1 > DefaultH then//wrapped string, so multiply
    incr = incr + ((strH1 / defaultH)*2)//to get a reasonable output, I have to multiply * 2, but I cant understand why
  end if
else
  incr = incr + strH2
  if strH2 > DefaultH then//wrapped string, so multiply
    incr = incr + ((strH2 / defaultH)*2)
  end if
end if
incr = incr + gap

next

Hello,
here is an example code I took out of one of my apps where I draw a string into an canvas:
https://cmezes.com/dl/TextDrawingExample.zip
I only tested it on OS X.

I’ll have a look. Thanks.

Hi,
after having a look at Christian’s TextDrawingExample, I wander if I actually have not understood at all the suggestions given in the various posts above (Michel, Sam, Thomas etc.).
So, were those suggestions implying that I should not depend on the graphics’ automatic wrapping, but I should instead break longer lines into 2, 3 , 4 chunks and feed drawString with each chunk?
Thanks for any suggestion.