Friday, September 25, 2015

More .NET monospace font nonsense

Just to make the point. Wikipedia defines a monospaced font as follows:

A monospaced font, also called a fixed-pitch, fixed-width, or non-proportional font, is a font whose letters and characters each occupy the same amount of horizontal space.
Now not everything you read on Wikipedia is necessarily true but I am confident that a technical reader would be happy with that definition.

You might be less happy to find that the .NET Graphics.DrawString() method does not adhere strictly to this approach. My earlier experience while trying to measure a monospaced font character width was a clue that issues might arise in actual usage. Arise they did.

You can’t see it at first but as printed lines become longer then it becomes clear that the line length is less than it should be. Pixels in the X axis are being “lost” along the way. My test data was printed at the correct register for the first 7 characters but the 8th was one pixel to the left of where it should have been. Somewhere around 90 plus characters into a line the positioning is out by 10 pixels (a single character width for the font in question).

Each character in every line is correctly positioned relative to the other lines but incorrectly positioned based upon any rational definition of a monospaced font.

The image below shows the 97th character (H) in the first line of text showing correctly in position while the second line rendered by the DrawString() method being passed the whole line of text shows the “H” well to the left of the correct location.

In case you wondered the blue “divider” is placed by an algorithm that looks for probable field positions by analysing transitions between character types (in this case a white space prior to a “letter”)

So if (like me) you are working in the .NET environment and you want to know where the nth character is on a “painted” surface of a window/control using (for crying out loud) a monospaced font – then you need to print each character individually at the correct location. On that basis, you could do just as well with a nominally proportional font of course.

At least this showed that, at longer string lengths, there was some consistency between MeasureString() and DrawString() even if both (in this instance) are wrong.

Programming in .NET is sometimes all about fighting .NET (or GDI+ or whatever is actually responsible for the rendering under the covers). On reflection, this is true of every software platform I have ever worked on.

Final word:
While subsequently working on something else completely, I found out that MeasureString() uses GDI+ while by default .DrawString() uses GDI and their rendering is not the same. Well we live and learn I suppose but you would have expected consistency within the .NET defaults wouldn't you?

No comments: