Forum > Graphics

how to query fixed font character width?


Martin V:

I need to query the character width in pixels of my fixed font.

This code works nearly fine:

Canvas.TextWidth ('X')

(The character can be an arbitrary one because of the fixed font.)

The code works on Windows and Linux, but causes malfunction in MacOSX. If I write a string with e.g. 50 characters, the positioning of the single characters within the string (only one Canvas.Textout) differs from positioning each character (50x Canvas.Textout with new X value calculated by TextWidth) about 2%. A dirty workaround is to use Canvas.Textout for each character, but this significantly slows down the program. Any ideas? Is there a font or canvas property where I can query the font character width? I tried Textwidth-1 and +1 and so on, but the differences are less than 1 pixel per character. These problems seem to be solved in the IDE.


Indeed on Mac (and probably in some future on other OS too) a char can have a width that includes decimals (e.g 6.1 pixel)

The IDE works around that by 2 steps:

- An awful amount of measuring to detect the case (see SynEditTextDrawer)

- Using ExtUTF8Out (same unit), which can be given a list as argument overwriting the width of each char, forcing the OS to draw the chars in the desired space.

SynEdit (the IDE) only uses this array, if necessary, since it slows down the output.

On top of this, there are some further easy to make mistakes:
- Even in a strictly monospaced fonts, there exist so called Full- and Half-width chars.
All latin are half width, some Chinese, Japanese, Arab, ... chars are Full width. they need twice the space.

- Your text may contain chars, that are not visible, or not visible on there own. Like combine utf8 chars, where an u-umlaut (2 dots on u) is 2 chars in the text: a none visible indicator char for umlaut, and a "u"

Edit: also you should be aware of overhang (TextMetrics). for example a kursive/italics char may partly hang into the cell of the next char.

If the next char is displayed by a separate TextOut (with opaque background), then the overhang may be cut off)
(This does sometimes happen in the IDE / still a TODO)

Martin V:
Thank you, ExtUtf8Out works:

--- Code: ---    arrw : array[1..255] of integer;

     for i := 1 to 255 do arrw[i]  := FontWidth;
     lclintf.ExtUTF8Out (Canvas.Handle, X, Y, 0, nil, PChar(utf8st), length(utf8st), @arrw);

--- End code ---
In the arrw array, you can assign every printed character of your line an own width.



[0] Message Index

Go to full version