Measuring width string

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

Measuring width string

Aliaksei Syrel
Hi

I'm sending it here so that it doesn't get lost.

There are multiple ways to measure string width. In the following examples performance will be tested measuring 10`000 times the width of the following string:

string := 'abcdefghijklmnopqrstuvwxyz 0123456789!@#$%^&*()_+'.

1) The most straightforward way is to send #widthOfString: to the font. Time to run gives around 250ms.
Resulting value is rounded to integer and seems to be not absolutely correct and precise.

2) More complex way is to go deeper on the level of glyphs and manually summarise the width of each character in the string sending #getGlyphWidth: character to the font. Time to run gives around 750ms.
Resulting value is float and looks like correct and precise value.

3) Even more complex is to use CairoFontMetricsProvider instead of font's methods. The same as in 2nd case we measure each character. Time to run around 350ms.
Resulting value is exactly the same as in the 2nd case. With almost equal performance to 1st it is nice alternative.

4) One more way is to let native cairo to calculate everything for us. Calls happen through nativeboost. Time to run around 120ms.
As result it returns CairoTextExtents which allows to calculate width and height with one call.

Cheers,
Alex
Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

Uko2
Hi Alex,

This is indeed a very useful information. You can also put it on StackOverflow, then it will be Googlable.

Cheers.
Uko


On 27 Oct 2015, at 12:02, Aliaksei Syrel <[hidden email]> wrote:

Hi

I'm sending it here so that it doesn't get lost.

There are multiple ways to measure string width. In the following examples performance will be tested measuring 10`000 times the width of the following string:

string := 'abcdefghijklmnopqrstuvwxyz 0123456789!@#$%^&*()_+'.

1) The most straightforward way is to send #widthOfString: to the font. Time to run gives around 250ms.
Resulting value is rounded to integer and seems to be not absolutely correct and precise.

2) More complex way is to go deeper on the level of glyphs and manually summarise the width of each character in the string sending #getGlyphWidth: character to the font. Time to run gives around 750ms.
Resulting value is float and looks like correct and precise value.

3) Even more complex is to use CairoFontMetricsProvider instead of font's methods. The same as in 2nd case we measure each character. Time to run around 350ms.
Resulting value is exactly the same as in the 2nd case. With almost equal performance to 1st it is nice alternative.

4) One more way is to let native cairo to calculate everything for us. Calls happen through nativeboost. Time to run around 120ms.
As result it returns CairoTextExtents which allows to calculate width and height with one call.

Cheers,
Alex

Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

Peter Uhnak
Note that you shouldn't use 2) or 3) for non-monospace fonts because of kerning.

font := StandardFonts defaultFont.
font widthOfString: 'eT'. "16"
font widthOfString: 'Te'. "15"

'eT' inject: 0 into: [ :width :c | width + (font getGlyphWidth: c) ]. "13.416015625"
'Te' inject: 0 into: [ :width :c | width + (font getGlyphWidth: c) ]. "13.416015625"

4) seems fine

font := StandardFonts defaultFont.
provider := CairoScaledFont fromFreetypeFont: font realFont.
width := [ :string |
converter := CairoUTF8Converter new.
converter convert: string from: 1 to: string size.
stringExtents := CairoTextExtents new.
provider getExtentsOf: converter buffer into: stringExtents.
stringExtents width ].

width value: 'eT'. "12.463638305664063"
width value: 'Te'. "12.561752319335938"


On Tue, Oct 27, 2015 at 12:27 PM, Yuriy Tymchuk <[hidden email]> wrote:
Hi Alex,

This is indeed a very useful information. You can also put it on StackOverflow, then it will be Googlable.

Cheers.
Uko



On 27 Oct 2015, at 12:02, Aliaksei Syrel <[hidden email]> wrote:

Hi

I'm sending it here so that it doesn't get lost.

There are multiple ways to measure string width. In the following examples performance will be tested measuring 10`000 times the width of the following string:

string := 'abcdefghijklmnopqrstuvwxyz 0123456789!@#$%^&*()_+'.

1) The most straightforward way is to send #widthOfString: to the font. Time to run gives around 250ms.
Resulting value is rounded to integer and seems to be not absolutely correct and precise.

2) More complex way is to go deeper on the level of glyphs and manually summarise the width of each character in the string sending #getGlyphWidth: character to the font. Time to run gives around 750ms.
Resulting value is float and looks like correct and precise value.

3) Even more complex is to use CairoFontMetricsProvider instead of font's methods. The same as in 2nd case we measure each character. Time to run around 350ms.
Resulting value is exactly the same as in the 2nd case. With almost equal performance to 1st it is nice alternative.

4) One more way is to let native cairo to calculate everything for us. Calls happen through nativeboost. Time to run around 120ms.
As result it returns CairoTextExtents which allows to calculate width and height with one call.

Cheers,
Alex


Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

Peter Uhnak
But #widthOfString: is definitely weird... like it's adding some extra space on the sides or something.

On Tue, Oct 27, 2015 at 12:50 PM, Peter Uhnák <[hidden email]> wrote:
Note that you shouldn't use 2) or 3) for non-monospace fonts because of kerning.

font := StandardFonts defaultFont.
font widthOfString: 'eT'. "16"
font widthOfString: 'Te'. "15"

'eT' inject: 0 into: [ :width :c | width + (font getGlyphWidth: c) ]. "13.416015625"
'Te' inject: 0 into: [ :width :c | width + (font getGlyphWidth: c) ]. "13.416015625"

4) seems fine

font := StandardFonts defaultFont.
provider := CairoScaledFont fromFreetypeFont: font realFont.
width := [ :string |
converter := CairoUTF8Converter new.
converter convert: string from: 1 to: string size.
stringExtents := CairoTextExtents new.
provider getExtentsOf: converter buffer into: stringExtents.
stringExtents width ].

width value: 'eT'. "12.463638305664063"
width value: 'Te'. "12.561752319335938"


On Tue, Oct 27, 2015 at 12:27 PM, Yuriy Tymchuk <[hidden email]> wrote:
Hi Alex,

This is indeed a very useful information. You can also put it on StackOverflow, then it will be Googlable.

Cheers.
Uko



On 27 Oct 2015, at 12:02, Aliaksei Syrel <[hidden email]> wrote:

Hi

I'm sending it here so that it doesn't get lost.

There are multiple ways to measure string width. In the following examples performance will be tested measuring 10`000 times the width of the following string:

string := 'abcdefghijklmnopqrstuvwxyz 0123456789!@#$%^&*()_+'.

1) The most straightforward way is to send #widthOfString: to the font. Time to run gives around 250ms.
Resulting value is rounded to integer and seems to be not absolutely correct and precise.

2) More complex way is to go deeper on the level of glyphs and manually summarise the width of each character in the string sending #getGlyphWidth: character to the font. Time to run gives around 750ms.
Resulting value is float and looks like correct and precise value.

3) Even more complex is to use CairoFontMetricsProvider instead of font's methods. The same as in 2nd case we measure each character. Time to run around 350ms.
Resulting value is exactly the same as in the 2nd case. With almost equal performance to 1st it is nice alternative.

4) One more way is to let native cairo to calculate everything for us. Calls happen through nativeboost. Time to run around 120ms.
As result it returns CairoTextExtents which allows to calculate width and height with one call.

Cheers,
Alex



Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

Thierry Goubier
In reply to this post by Aliaksei Syrel
Hi Alex,

thanks, this is very usefull. Can you tell which one of these measures is the closest to the effective length of a string morph? Number 4?

Thierry

2015-10-27 12:02 GMT+01:00 Aliaksei Syrel <[hidden email]>:
Hi

I'm sending it here so that it doesn't get lost.

There are multiple ways to measure string width. In the following examples performance will be tested measuring 10`000 times the width of the following string:

string := 'abcdefghijklmnopqrstuvwxyz 0123456789!@#$%^&*()_+'.

1) The most straightforward way is to send #widthOfString: to the font. Time to run gives around 250ms.
Resulting value is rounded to integer and seems to be not absolutely correct and precise.

2) More complex way is to go deeper on the level of glyphs and manually summarise the width of each character in the string sending #getGlyphWidth: character to the font. Time to run gives around 750ms.
Resulting value is float and looks like correct and precise value.

3) Even more complex is to use CairoFontMetricsProvider instead of font's methods. The same as in 2nd case we measure each character. Time to run around 350ms.
Resulting value is exactly the same as in the 2nd case. With almost equal performance to 1st it is nice alternative.

4) One more way is to let native cairo to calculate everything for us. Calls happen through nativeboost. Time to run around 120ms.
As result it returns CairoTextExtents which allows to calculate width and height with one call.

Cheers,
Alex

Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

Peter Uhnak
Yes, this is an important insight,
I've made a visual comparison of #4 (red) compared to #1 (blue)

plus compared to the other ones it can even tell the height... now to teach Roassal how to use it...

Peter

On Tue, Oct 27, 2015 at 4:11 PM, Thierry Goubier <[hidden email]> wrote:
Hi Alex,

thanks, this is very usefull. Can you tell which one of these measures is the closest to the effective length of a string morph? Number 4?

Thierry


2015-10-27 12:02 GMT+01:00 Aliaksei Syrel <[hidden email]>:
Hi

I'm sending it here so that it doesn't get lost.

There are multiple ways to measure string width. In the following examples performance will be tested measuring 10`000 times the width of the following string:

string := 'abcdefghijklmnopqrstuvwxyz 0123456789!@#$%^&*()_+'.

1) The most straightforward way is to send #widthOfString: to the font. Time to run gives around 250ms.
Resulting value is rounded to integer and seems to be not absolutely correct and precise.

2) More complex way is to go deeper on the level of glyphs and manually summarise the width of each character in the string sending #getGlyphWidth: character to the font. Time to run gives around 750ms.
Resulting value is float and looks like correct and precise value.

3) Even more complex is to use CairoFontMetricsProvider instead of font's methods. The same as in 2nd case we measure each character. Time to run around 350ms.
Resulting value is exactly the same as in the 2nd case. With almost equal performance to 1st it is nice alternative.

4) One more way is to let native cairo to calculate everything for us. Calls happen through nativeboost. Time to run around 120ms.
As result it returns CairoTextExtents which allows to calculate width and height with one call.

Cheers,
Alex


Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

Sven Van Caekenberghe-2

> On 04 Nov 2015, at 01:15, Peter Uhnák <[hidden email]> wrote:
>
> Yes, this is an important insight,
> I've made a visual comparison of #4 (red) compared to #1 (blue)
> <dimensions.png>
> ​http://ws.stfx.eu/LWMJN1SY7VXT

Peter, this script is soo cool, really great work !

> plus compared to the other ones it can even tell the height... now to teach Roassal how to use it...
>
> Peter
>
> On Tue, Oct 27, 2015 at 4:11 PM, Thierry Goubier <[hidden email]> wrote:
> Hi Alex,
>
> thanks, this is very usefull. Can you tell which one of these measures is the closest to the effective length of a string morph? Number 4?
>
> Thierry
>
>
> 2015-10-27 12:02 GMT+01:00 Aliaksei Syrel <[hidden email]>:
> Hi
>
> I'm sending it here so that it doesn't get lost.
>
> There are multiple ways to measure string width. In the following examples performance will be tested measuring 10`000 times the width of the following string:
>
> string := 'abcdefghijklmnopqrstuvwxyz 0123456789!@#$%^&*()_+'.
>
> 1) The most straightforward way is to send #widthOfString: to the font. Time to run gives around 250ms.
> http://ws.stfx.eu/2Q5YA9DFTRDR
> Resulting value is rounded to integer and seems to be not absolutely correct and precise.
>
> 2) More complex way is to go deeper on the level of glyphs and manually summarise the width of each character in the string sending #getGlyphWidth: character to the font. Time to run gives around 750ms.
> http://ws.stfx.eu/ETBEW1EHAAZ8
> Resulting value is float and looks like correct and precise value.
>
> 3) Even more complex is to use CairoFontMetricsProvider instead of font's methods. The same as in 2nd case we measure each character. Time to run around 350ms.
> http://ws.stfx.eu/7I89DMD0ZLM3
> Resulting value is exactly the same as in the 2nd case. With almost equal performance to 1st it is nice alternative.
>
> 4) One more way is to let native cairo to calculate everything for us. Calls happen through nativeboost. Time to run around 120ms.
> http://ws.stfx.eu/HYD76OMIOM7L 
> As result it returns CairoTextExtents which allows to calculate width and height with one call.
>
> Cheers,
> Alex
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

Thierry Goubier


2015-11-04 8:34 GMT+01:00 Sven Van Caekenberghe <[hidden email]>:

> On 04 Nov 2015, at 01:15, Peter Uhnák <[hidden email]> wrote:
>
> Yes, this is an important insight,
> I've made a visual comparison of #4 (red) compared to #1 (blue)
> <dimensions.png>
> ​http://ws.stfx.eu/LWMJN1SY7VXT

Peter, this script is soo cool, really great work !

I like the 'whatever' :)

Thierry
 
> plus compared to the other ones it can even tell the height... now to teach Roassal how to use it...
>
> Peter
>
> On Tue, Oct 27, 2015 at 4:11 PM, Thierry Goubier <[hidden email]> wrote:
> Hi Alex,
>
> thanks, this is very usefull. Can you tell which one of these measures is the closest to the effective length of a string morph? Number 4?
>
> Thierry
>
>
> 2015-10-27 12:02 GMT+01:00 Aliaksei Syrel <[hidden email]>:
> Hi
>
> I'm sending it here so that it doesn't get lost.
>
> There are multiple ways to measure string width. In the following examples performance will be tested measuring 10`000 times the width of the following string:
>
> string := 'abcdefghijklmnopqrstuvwxyz 0123456789!@#$%^&*()_+'.
>
> 1) The most straightforward way is to send #widthOfString: to the font. Time to run gives around 250ms.
> http://ws.stfx.eu/2Q5YA9DFTRDR
> Resulting value is rounded to integer and seems to be not absolutely correct and precise.
>
> 2) More complex way is to go deeper on the level of glyphs and manually summarise the width of each character in the string sending #getGlyphWidth: character to the font. Time to run gives around 750ms.
> http://ws.stfx.eu/ETBEW1EHAAZ8
> Resulting value is float and looks like correct and precise value.
>
> 3) Even more complex is to use CairoFontMetricsProvider instead of font's methods. The same as in 2nd case we measure each character. Time to run around 350ms.
> http://ws.stfx.eu/7I89DMD0ZLM3
> Resulting value is exactly the same as in the 2nd case. With almost equal performance to 1st it is nice alternative.
>
> 4) One more way is to let native cairo to calculate everything for us. Calls happen through nativeboost. Time to run around 120ms.
> http://ws.stfx.eu/HYD76OMIOM7L
> As result it returns CairoTextExtents which allows to calculate width and height with one call.
>
> Cheers,
> Alex
>
>



Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

Stephan Eggermont-3
In reply to this post by Peter Uhnak
Nice. So trying with #Ta and #ffl I noticed that there is no kerning (at
least not correct) but there are ligatures.

Stephan



Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

Aliaksei Syrel
StandardFonts defaultFont
 
"a LogicalFont
 familyName: Source Sans Pro
 emphasis: nil
 pointSize: 10
 realFont: FreeTypeFont('Source Sans Pro' 'Regular' 10) weight: 400 stretch: 5 slant: 0" 

StandardFonts defaultFont realFont
 
"FreeTypeFont('Source Sans Pro' 'Regular' 10)" 

StandardFonts defaultFont realFont face hasKerning

"false"

Free type source sans pro in Pharo just does not support kerning.

Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

Aliaksei Syrel
However, Helvetica Neue on mac has kerning.
Will check

Cheers,
Alex

On Wed, Nov 4, 2015 at 1:59 PM, Aliaksei Syrel <[hidden email]> wrote:
StandardFonts defaultFont
 
"a LogicalFont
 familyName: Source Sans Pro
 emphasis: nil
 pointSize: 10
 realFont: FreeTypeFont('Source Sans Pro' 'Regular' 10) weight: 400 stretch: 5 slant: 0" 

StandardFonts defaultFont realFont
 
"FreeTypeFont('Source Sans Pro' 'Regular' 10)" 

StandardFonts defaultFont realFont face hasKerning

"false"

Free type source sans pro in Pharo just does not support kerning.


Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

Aliaksei Syrel
Ok, answer is quite simple.
Current string rendering on athens does not support kerning. Because it is not cairo's job. Kerning should be took into account after creating glyphs with cairo but before extent measurement and obviously rendering. It can be done with FreeType.
I made small refactoring of text measurement and added kerning support. 

So, in the latest version of Athens-Cairo you can get extents easily:

extents := CairoFontMetricsProvider new
font: StandardFonts defaultFont;
extentsOf: 'Ta ffl'.

extent is an instance of CairoTextExtents.

Rendering on athens with Times New Roman size 200 gives: (Mac OSX Yosemite)

Inline image 1

And here is what I get in Keynote with the same font

Inline image 2

Close enough :D



Cheers,
Alex

On Wed, Nov 4, 2015 at 2:04 PM, Aliaksei Syrel <[hidden email]> wrote:
However, Helvetica Neue on mac has kerning.
Will check

Cheers,
Alex

On Wed, Nov 4, 2015 at 1:59 PM, Aliaksei Syrel <[hidden email]> wrote:
StandardFonts defaultFont
 
"a LogicalFont
 familyName: Source Sans Pro
 emphasis: nil
 pointSize: 10
 realFont: FreeTypeFont('Source Sans Pro' 'Regular' 10) weight: 400 stretch: 5 slant: 0" 

StandardFonts defaultFont realFont
 
"FreeTypeFont('Source Sans Pro' 'Regular' 10)" 

StandardFonts defaultFont realFont face hasKerning

"false"

Free type source sans pro in Pharo just does not support kerning.



Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

Tudor Girba-2
This is one beautiful piece of work!

Doru

On Wed, Nov 4, 2015 at 3:51 PM, Aliaksei Syrel <[hidden email]> wrote:
Ok, answer is quite simple.
Current string rendering on athens does not support kerning. Because it is not cairo's job. Kerning should be took into account after creating glyphs with cairo but before extent measurement and obviously rendering. It can be done with FreeType.
I made small refactoring of text measurement and added kerning support. 

So, in the latest version of Athens-Cairo you can get extents easily:

extents := CairoFontMetricsProvider new
font: StandardFonts defaultFont;
extentsOf: 'Ta ffl'.

extent is an instance of CairoTextExtents.

Rendering on athens with Times New Roman size 200 gives: (Mac OSX Yosemite)

Inline image 1

And here is what I get in Keynote with the same font

Inline image 2

Close enough :D



Cheers,
Alex

On Wed, Nov 4, 2015 at 2:04 PM, Aliaksei Syrel <[hidden email]> wrote:
However, Helvetica Neue on mac has kerning.
Will check

Cheers,
Alex

On Wed, Nov 4, 2015 at 1:59 PM, Aliaksei Syrel <[hidden email]> wrote:
StandardFonts defaultFont
 
"a LogicalFont
 familyName: Source Sans Pro
 emphasis: nil
 pointSize: 10
 realFont: FreeTypeFont('Source Sans Pro' 'Regular' 10) weight: 400 stretch: 5 slant: 0" 

StandardFonts defaultFont realFont
 
"FreeTypeFont('Source Sans Pro' 'Regular' 10)" 

StandardFonts defaultFont realFont face hasKerning

"false"

Free type source sans pro in Pharo just does not support kerning.






--

"Every thing has its own flow"
Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

Stephan Eggermont-3
In reply to this post by Aliaksei Syrel
On 04/11/15 15:51, Aliaksei Syrel wrote:
> Ok, answer is quite simple.
> Current string rendering on athens does not support kerning. Because it
> is not cairo's job. Kerning should be took into account _after_ creating
> glyphs with cairo but _before_ extent measurement and obviously
> rendering. It can be done with FreeType.
> I made small refactoring of text measurement and added kerning support.

Really nice.

Stephan




Reply | Threaded
Open this post in threaded view
|

Re: Measuring width string

stepharo
In reply to this post by Tudor Girba-2
yes I want beautiful fonts in Pharo :)


Le 4/11/15 18:14, Tudor Girba a écrit :
This is one beautiful piece of work!

Doru

On Wed, Nov 4, 2015 at 3:51 PM, Aliaksei Syrel <[hidden email]> wrote:
Ok, answer is quite simple.
Current string rendering on athens does not support kerning. Because it is not cairo's job. Kerning should be took into account after creating glyphs with cairo but before extent measurement and obviously rendering. It can be done with FreeType.
I made small refactoring of text measurement and added kerning support. 

So, in the latest version of Athens-Cairo you can get extents easily:

extents := CairoFontMetricsProvider new
font: StandardFonts defaultFont;
extentsOf: 'Ta ffl'.

extent is an instance of CairoTextExtents.

Rendering on athens with Times New Roman size 200 gives: (Mac OSX Yosemite)

Inline image 1

And here is what I get in Keynote with the same font

Inline image 2

Close enough :D



Cheers,
Alex

On Wed, Nov 4, 2015 at 2:04 PM, Aliaksei Syrel <[hidden email]> wrote:
However, Helvetica Neue on mac has kerning.
Will check

Cheers,
Alex

On Wed, Nov 4, 2015 at 1:59 PM, Aliaksei Syrel <[hidden email]> wrote:
StandardFonts defaultFont
 
"a LogicalFont
 familyName: Source Sans Pro
 emphasis: nil
 pointSize: 10
 realFont: FreeTypeFont('Source Sans Pro' 'Regular' 10) weight: 400 stretch: 5 slant: 0" 

StandardFonts defaultFont realFont
 
"FreeTypeFont('Source Sans Pro' 'Regular' 10)" 

StandardFonts defaultFont realFont face hasKerning

"false"

Free type source sans pro in Pharo just does not support kerning.






--

"Every thing has its own flow"