(Note 1: In this article, when I use the word "label
", I refer to the text (to be) printed on screen, not the winforms label
control itself. Even though in my application, I used a simple label
to display my texts/labels, I could have used DrawString()
instead, the main point is the same now.
Note 2: I used FontFamily.GenericSansSerif
font family. This displays SansSerif named font, stock shipped with my Windows 7. Actually, the whole application is designed for measuring regular SansSerif font labels.)
Introduction
In the last few weeks I have been designing a reaction time measurement tool for a cognitine sciences project. I can't use E-Prime or DMDX because of my current project goals, so I chose to make my application in C#.
(Note: Anyway, please keep in mind that .NET GDI applications are not suitable for precise reaction time measurement. Even 20-70 ms delays may eventually appear on stimulus presentation, but in my case that was tolerable.)
In my reaction time measurement application, I have to set the height of graphical elements with good precision based on the user's/subject's view angle. This first seemed to mean no problem, because it is easy to calculate the desired height (in pixels) of a graphical element (for example a label) if we know the DPI values of the monitor, the view angle, and the distance between perspective point and screen plane (~20 inches according to human factors standards).
The first problem I encountered was that when I set the height (in GraphicsUnit.Pixel
units) of a label with the Font
constructor, the real height of the displayed label was much lower.
The second problem was that, when I wanted to measure a label height with MeasureString.Height
, it returned much higher values than the real height of label letters.
(Nice detailed information on this can be found here.
I decided to write a separate application (the one which is discussed in this article) only for the purpose of measuring my labels that I will use in my reaction time measurement project. This is how I began my journey.
Background
I decided to measure the difference between reality (printscreened labels that I measured "by hand") and Font
size parameter that I set in my code, and these measurements gave me important data. I could plot this data as points that fit on a line. I could see a connection as a linear function between the size I told the Font
constructor and the real height of the label. Then, I could easily create a correction function.
I also plotted the differences between reality and MeasureString.Height
and even MeasureString.Width
too (but only for labels without kerning (https://en.wikipedia.org/wiki/Kerning)).
For example, this is how my manual measurements data looked like in Excel plot (blue dotted line):
(Here, the x axis shows desired height value in px that I gave to the Font
constructor, and the y axis shows actual height that I could measure on the label drawn on screen. Grey dotted line shows the invert of the function that I observed as the rule of differences. Yellow dotted line shows the corrected function.)
I found basically four types (https://en.wikipedia.org/wiki/Typeface#Font_metrics) of labels (depending on the max height of any letter in that label) that would need different correction functions:
- the label contains Normal height letters only [eg.: m n o c v x e a]
- the label contains Ascender letters (and perhaps also Normal ones) [eg.: i ő t f l 1 B T C L]
Anyway, in the font I used (SansSerif), all capital letters and numbers are Ascenders too - the label contains Descender letters (and perhaps also Normal ones) [eg.: p y g q ]
- the label contains Ascenders and Descenders too (or the character 'j' which is both at the same time) [e.g., the
string
"Spring
"]
In these different cases, letter diversity causes the label to have different height in total (if we imagine it in a tight boundary box that is perfectly trimmed to the pixels of the label drawn on screen). So I had to define different correction functions for each of these cases.
In total, I found:
- 4 correction functions for giving the
Font
constructor what it needs as font height (font size) to produce the desired label height in pixels - 4 correction functions for the far-from-reality
MeasureString.Height
values - 1 correction function for
MeasureString.Width
(I only defined it for labels without kerning)
These are demonstrated in my application, you will find the compiled binary named "calculateViewAngle.exe".
Long Story Short
You can set the height of the label to be displayed in user's view angle. The program automatically recognizes your input text, and tells what "label type" it belongs to, then shows the specific correction functions that you can use If you want to display the text "precisely" in your GDI application. One more useful function of the program is that it can estimate the width in view angle of the given label.
The program code may be a bit scratchy, but can be understood I guess.
Although I wrote this program for my specific purposes, I think it may be useful for other problems too.
I hope that this little application will help you, if you got in trouble with precisely measuring label height.
It may contain small mistakes, one reason is that I had a limited amount of time to make it, the other is that I am still on a kind of beginner level yet.
Thanks for your interest!
History