MeasureStringHeight problem

klaus

Expert
Licensed User
Longtime User
Hi Erel,

How is MeasureStringHeight calculated ?

I would like to know the total height of a text line.

With the defaut TypeFace
MeasureStringHeight("M",14) = 10
MeasureStringHeight("a",14) = 8
MeasureStringHeight("h",14) = 11
MeasureStringHeight("g",14) = 12
These values give the height of the given character.

MeasureStringHeight("Mhy",14) = 10 should be 15
It seems that only the first character is taken into account.

With 3 heighs it is possible to calculate the total height of a line but still not with the space between the lines.

MeasureStringHeight("Mhy"&CRLF&"Mhy",14) = 10
Will multiline be taken into account ?

In B4PPC all the single line strings give the same value and a double line gives the double, it seems always beeing the total line height.

I think that giving just the line height would be enough like in B4PPC, or add the total line height value.

Best regards.

 
Last edited:

agraham

Expert
Licensed User
Longtime User
You are correct! MeasureStringHeight seems to only measure the first character and "returns the height of the smallest rectangle that encloses all of the characters", in this case the first. So it is measuring the individual character size and not the nominal typeface size including ascenders and descenders which the Compact Framework does.

I think Erel could improve on this by measuring the complete string.
 

NFOBoy

Active Member
Licensed User
Longtime User
Erel,

I know this has been a while since this thread was last used, but it seemed the best place to ask my question.

I am also using measurescreenheight, but with Thai script, and came upon an interesting error.


cv.MeasureStringHeight( "ฦื้พุเลือกเสียง", typeface.default, 20) returns size 41
cv.MeasureStringHeight( "เลือกเสียง",Typeface.default, 20) returns size 26

The difference being that (i can tell) characters fall below the bottom (of the place where the characters "sit") as well.

I'm using this to calculate required fontsize at runtime, as I use %x and %y to build views, and want the font to look good across all devices/orientations, so I needed some code that would give me the biggest font I could use on labels (or other views), with different orientations, and different fonts (based on user preference). This particular function is designed to find the largest font possible for height/width limitations of the label, for a set of words, so that I can use that fontsize across all the labels of that same size, and the largest one fits nicely (the other words won't quite use all the space available, but everything looks uniform)

B4X:
Sub SetFontSizeRadioOrLabel(textArray() As String, desiredFont As Typeface, desiredView As View) As Float
'this sub will go thru and pick out the smallest size font for the set of textArray to fit in a view of the same size
'this will then return the fontsize that works for all strings in the array

Dim smallestFontSize As Float
smallestFontSize = 0

Dim languageFactor As Float
languageFactor = 1

Dim cv As Canvas
cv.Initialize(desiredView)

For i = 0 To textArray.Length - 1
   If textArray(i).Trim = Null OR textArray(i).Length < 1 Then
      'do nothing with this one
   Else
      Dim sizeFontinLoop As Float 'holds the font as it goes thru
      sizeFontinLoop = 1
      Dim countIncrement As Float 'for counting in powers of 10
      countIncrement = 10
      Do While countIncrement > .01
         Do While cv.MeasureStringWidth(textArray(i), desiredFont, sizeFontinLoop ) < (desiredView.width * languageFactor)
            sizeFontinLoop = sizeFontinLoop + countIncrement
         Loop
         sizeFontinLoop = sizeFontinLoop - countIncrement
         countIncrement = countIncrement * .1
         Loop

      'at the end of these loops... sizefontinloop holds the fontsize for the text at i
      If smallestFontSize = 0 Then
         smallestFontSize = sizeFontinLoop
      Else
         If sizeFontinLoop < smallestFontSize Then
            smallestFontSize = sizeFontinLoop
         End If
      End If      
   End If
Next

'For i = 0 To textArray.Length - 1
'   If textArray(i).Trim = Null OR textArray(i).Length < 1 Then
'      'do nothing with this one
'   Else
'      Dim sizeFontinLoop As Float 'holds the font as it goes thru
'      sizeFontinLoop = 1
'      Dim countIncrement As Float 'for counting in powers of 10
'      countIncrement = 10
'      Do While countIncrement > .01
'         Do While cv.MeasureStringHeight(textArray(i), desiredFont, sizeFontinLoop ) < (desiredLabel.height * languageFactor)
'            sizeFontinLoop = sizeFontinLoop + countIncrement
'         '   Msgbox (sizeFontinLoop, "sizefontinloop")
'         Loop
'         sizeFontinLoop = sizeFontinLoop - countIncrement
'         countIncrement = countIncrement * .1
'         ''Msgbox (countIncrement, "countincremet")
'      Loop
'
'      'at the end of these loops... sizefontinloop holds the fontsize for the text at i
'      If smallestFontSize = 0 Then
'         smallestFontSize = sizeFontinLoop
'      Else
'         If sizeFontinLoop < smallestFontSize Then
'            smallestFontSize = sizeFontinLoop
'         End If
'      End If      
'   End If
'Next

'for some reason, this code works for all of the fonts.. not sure why???  but using it!

      Dim sizeFontinLoop As Float 'holds the font as it goes thru
      sizeFontinLoop = 1
      Dim countIncrement As Float 'for counting in powers of 10
      countIncrement = 10
      Do While countIncrement > .01
         Do While cv.MeasureStringHeight(  "ฦื้พุเลือกเสียง", desiredFont, sizeFontinLoop ) < (desiredView.height)
            sizeFontinLoop = sizeFontinLoop + countIncrement
         '   Msgbox (sizeFontinLoop, "sizefontinloop")
         Loop
         sizeFontinLoop = sizeFontinLoop - countIncrement
         countIncrement = countIncrement * .1
         ''Msgbox (countIncrement, "countincremet")
      Loop
      
      If smallestFontSize = 0 Then
         smallestFontSize = sizeFontinLoop
      Else
         If sizeFontinLoop < smallestFontSize Then
            smallestFontSize = sizeFontinLoop
         End If
      End If   
Return smallestFontSize

End Sub


when I tested out the code originally, I found that english and japanese characters worked perfectly where width was the deciding factor for returning smallest font that would work. For height, they were a bit too big, which is where I have the code for Language Factor in the commented out part in the middle.

But Thai script was just way off the mark for width and height, so I had put in a language factor for width for Thai, and a language Factor for English/Japanese for height.

As I was working on the language Factor setting for Thai in height mode (testing various resolutions/words), I used the symbols "ฦื้พุเลือกเสียง" and *snap*, not only did Thai look good in width and height limited labels, but with No language factor! (which is what I thought should work with my code anyway, but fonts sure seem to be nutty) Too be completely honest though, I don't think I have found a solution for the width problem, as I think my Thai characters are almost always limited by height in my code... but it's working...


So then I tried english/japanese again, but with that same word from thai thrown in for the height test, and *snap* they looked good on height limited labels (with no language factor required) and the original already worked for them on width limited, so as my code says, I don't know why that works, but I'm going with it.

I thought maybe you could tell why measureStringWidth/measureStringHeight are so funky with Thai?

FYI, if it matters for how they do their calculations, Thai script can build left/right (just like english/japanese) and up/down. similiar to perhaps how adding a comma in the word isn't, except that the characters don't stand on their own. i.e. a comma ' is to the left or right of some other character. ั (this is maihahnahnguad) and it HAS to be on top of character... but this is ้ maitoh, and it ALSO has to go on the top, and is stackable ดั็, like that! So that is three characters, that all go on the same space (nothing left or right)

If that makes sense, does that explain why measureStringWidth/Height don't work so well with Thai?


Ross
 

NFOBoy

Active Member
Licensed User
Longtime User
No worries... again, I don't understand why it works either... at least I don't understand why Thai Script that doesn't have characters that aren't "stacked" measure so wierd, and get such bad values back from them...

As long as it works... then I'm happy! :)
 
Top