In this section we will concentrate on fonts. The discussion starts with a description of the types of fonts in the Windows operating system, followed by a little background material on fonts. After these basic concepts are covered, the discussion turns to how fonts are handled in GDI+ and .NET.
5.3.1 Font Types in Windows
Windows supports two types of fonts: GDI fonts and device fonts. Device fonts are native to output devices such as a monitor or a printer. GDI fonts are stored in files on your systemnormally in the WindowsFonts directory. Each font has its own file. For example, Arial, Arial Black, Arial Bold, Arial Italic, Arial Black Italic, Arial Bold Italic, Arial Narrow, Arial Narrow Bold Italic, and Arial Narrow Italic are different fonts in the Arial font family, and each one has its own file (see Figure 5.5).
Figure 5.5. Fonts available in Windows
GDI fonts can be further divided into four major categories: raster, stroke, TrueType, and OpenType. The raster and stroke fonts are the oldest way to display text (they pre-date Windows 3.1!). Raster fonts (also known as bitmap fonts) store each character in pixel format. Each raster font is designed for a specific aspect ratio and character size, which are generally not scalable to other sizes. The main advantage of raster fonts is high performance because rendering a raster font usually just requires copying it to video memory. Raster fonts support boldface, italics, underlining, and strikethrough formatting.
Stroke fonts (also known as vector fonts) are defined as a series of lines and dotsin much the same way that characters are drawn with a pen plotter. Stroke fonts are thus quite scalable (they can be increased or decreased to any size), and they can be used with output devices of any resolution. Examples of stroke fonts include Modern, Roman, and Script. Like raster fonts, stroke fonts support boldface, italics, underlining, and strikethrough formatting.
Next we come to TrueType fonts, which were developed by Apple and Microsoft and are supported by many manufacturers. TrueType fonts are also called outline fonts because the individual characters are defined by filled outlines of straight lines and curves. Altering the coordinates that define the outlines provides great scalability. The original 13 TrueType fonts were
Adobe and Microsoft announced yet another format in 1997, called OpenType. It is a combination of TrueType and the Type 1 outline format of Adobe's page-description language. Windows 2000 installs 82 fonts, including TrueType fonts, OpenType fonts, and other types. The TrueType fonts are represented by a "T" icon, and OpenType fonts are represented by an "O" icon in Windows Explorer, as shown in Figure 5.6.
Figure 5.6. Font icons represent font types
The file extension of both TrueType and OpenType fonts is .ttf. If you double-click on the Verdana OpenType font file, it displays the information shown in Figure 5.7.
Figure 5.7. An OpenType font
The Arial Black Italic TrueType font file, on the other hand, looks like Figure 5.8.
Figure 5.8. A TrueType font
In 1998, Microsoft announced a new display technology called ClearType. ClearType increases the readability and smoothness of text on existing LCDs (liquid crystal displays), such as laptop screens, flat-screen monitors, and Pocket PC screens. In normal displays, a pixel has only two states: on and off. ClearType technology adds additional information to a pixel besides the on and off states. With ClearType, the words on the display device look almost as sharp and clear as those on the printed page.
Note
To learn more about Microsoft's ClearType technology, visit http://www.microsoft.com/typography/cleartype/default.htm.
5.3.1.1 Attributes or Styles
In typography, the combination of a typeface name (sometimes referred to as a face name) and a point size (sometimes referred to as the em size) represents a font. A typeface name is a combination of a font family and the font style (also referred to as font attributes). Each typeface belongs to a font family such as Times New Roman, Arial, or Courier. The Courier family, for example, includes the typefaces Courier New, Courier New Bold, and Courier New Italic.
Generally, when we talk about a font, we are referring to more than just one component. A typical font is a combination of three components: font family, font style, and font size. Figure 5.9 shows the components of a typical font.
Figure 5.9. Font components
A complete example of a font is "Times New Roman, size 10, Bold|Italic". Here the font family is Times New Roman, the size is 10-point, and the style is both bold and italic.
5.3.1.2 Font Height and Line Spacing
The size of a font is expressed in points, where a point is usually 1/72 (0.013888) inch. The measurement of the size of a font is a little confusing because characters have different heights. If all alphabetic characters had the same height, it would be easier to calculate the size of a font. For example, consider the characters b and q. Technically they have the same height (or size), but they are situated in different locations along a straight line. In other words, the character's size may not be the same as the point size, also called em size. The font size is related to the line spacing. We will discuss line spacing in more detail in Section 5.3.4.
5.3.2 Fonts in .NET
Before we use fonts and draw text, let's see what classes GDI+ provides related to text and fonts, and how to use them.
The Font class provides functionality for fonts, including methods and properties to define functionalities such as font style, size, name, and conversions. Before we discuss the Font class, we will introduce the FontStyle enumeration and the FontFamily class, which we will use to create Font objects.
5.3.3 The FontStyle Enumeration
The FontStyle enumeration defines the common styles of a font. The members of FontStyle are described in Table 5.4.
5.3.4 The FontFamily Class
The FontFamily class provides methods and properties to work with font families. Table 5.5 describes the properties of the FontFamily class.
Member |
Description |
---|---|
Bold |
Bold text |
Italic |
Italic text |
Regular |
Normal text |
Strikeout |
Text with a line through the middle |
Underline |
Underlined text |
Property |
Description |
---|---|
Families |
Returns an array of all the font families associated with the current graphics context. |
GenericMonospace |
Returns a monospace font family. |
GenericSansSerif |
Returns a sans serif font family. |
GenericSerif |
Returns a serif font family. |
Name |
Returns the name of a font family. |
Note
The GetFamilies method of the FontCollection class returns all families, as we will discuss in Section 5.6.
Table 5.6 describes the methods of the FontFamily class.
Table 5.6 introduces some new terms, including base line, ascent, and descent. Let's see what they mean. Figure 5.10 shows a typical font in Windows. As you can see, although the letters b and q are the same size, their starting points and ending points (top and bottom locations) are different. The total height of a fontincluding ascent, descent, and extra spaceis called the line spacing. Ascent is the height above the base line, and descent is the height below the base line. As Figure 5.10 shows, two characters may have different positions along the base line. For some fonts, the extra value is 0, but for others it is not.
Figure 5.10. Font metrics
Method |
Description |
---|---|
GetCellAscent |
Returns the cell ascent, in font design units, of a font family. |
GetCellDescent |
Returns the cell descent, in font design units, of a font family. |
GetEmHeight |
Returns the height, in font design units, of the em square for the specified style. |
GetFamilies |
Returns an array that contains all font families available for a graphics object. This method takes an argument of Graphics type. |
GetLineSpacing |
Returns the amount of space between two consecutive lines of text for a font family. |
GetName |
Returns the name, in the specified language, of a font family. |
IsStyleAvailable |
Before applying a style to a font, you may want to know whether the font family in question supports that style. This method returns true if a font style is available. For example, the following code snippet checks whether or not the Arial font family supports italics: FontFamily ff = new FontFamily("Arial"); if(ff.IsStyleAvailable(FontStyle.Italic)) // do something |
For some fonts, line spacing is the sum of ascent and descent. Listing 5.6 creates a new font; uses get methods to get the values of line spacing, ascent, and descent; and calculates the extra space by subtracting ascent and descent from the line space. The following list identifies the get methods of a FontFamily object:
In addition to these get methods, the Font class provides GetHeight, which returns the height of a Font object.
As Listing 5.6 shows, we use GetLineSpacing, GetLineAscent, GetLineDescent, and GetEmHeight to get line spacing, ascent, descent, and font height, respectively, and then we display the output in a message box.
Listing 5.6 Getting line spacing, ascent, descent, and font height
private void Properties_Click(object sender, System.EventArgs e) { // Create a Graphics object Graphics g = this.CreateGraphics(); // Create a Font object Font fnt = new Font("Verdana", 10); // Get height float lnSpace = fnt.GetHeight(g); // Get line spacing int cellSpace = fnt.FontFamily.GetLineSpacing(fnt.Style); // Get cell ascent int cellAscent = fnt.FontFamily.GetCellAscent(fnt.Style); // Get cell descent int cellDescent = fnt.FontFamily.GetCellDescent(fnt.Style); // Get font height int emHeight = fnt.FontFamily.GetEmHeight(fnt.Style); // Get free space float free = cellSpace - (cellAscent + cellDescent); // Display values string str = "Cell Height:" + lnSpace.ToString() + ", Line Spacing: "+cellSpace.ToString() + ", Ascent:"+ cellAscent.ToString() + ", Descent:"+ cellDescent.ToString() + ", Free:"+free.ToString() + ", EM Height:"+ emHeight.ToString() ; MessageBox.Show(str.ToString()); // Dispose of objects fnt.Dispose(); g.Dispose(); }
Figure 5.11 shows the output from Listing 5.6. We get cell height, line spacing, ascent, descent, free (extra) space, and em height.
Figure 5.11. Getting line spacing, ascent, descent, free (extra) space, and height of a font
5.3.5 The GraphicsUnit Enumeration
You can define the unit of measure of a font when you construct a Font object. The Font class constructor takes an argument of type GraphicsUnit enumeration, which specifies the unit of measure of a font. The default unit of measure for fonts is the point (1/72 inch). You can get the current unit of a font by using the Unit property of the Font class. The following code snippet returns the current unit of the font:
Font fnt = new Font("Verdana", 10); MessageBox.Show(fnt.Unit.ToString());
The members of the GraphicsUnit enumeration are described in Table 5.7.
Member |
Unit of Measure |
---|---|
Display |
1/75 inch |
Document |
1/300 inch |
Inch |
1 inch |
Millimeter |
1 millimeter |
Pixel |
1 pixel |
Point |
1/72 inch |
World |
The world unit (we'll discuss world coordinates in Chapter 10) |
5.3.6 The Font Class
The Font class combines a font and methods and properties to define functionalities such as font style, size, name, and conversions. Table 5.8 describes the properties of the Font class.
The following code creates a Font object of font family Arial with size 16 and uses the Font class properties to find out the details of the Font object.
Font arialFont = new Font( "Arial", 16, FontStyle.Bold|FontStyle.Underline|FontStyle.Italic); MessageBox.Show("Font Properties = Name:"+arialFont.Name +" Size:"+arialFont.Size.ToString() +" Style:"+ arialFont.Style.ToString() +" Default Unit:"+ arialFont.Unit.ToString() +" Size in Points:"+ arialFont.SizeInPoints.ToString());
The Font class provides three static methods: FromHdc, FromHfont, and FromLogFont. These methods create a Font object from a window handle to a device context, a window handle, and a GDI LOGFONT structure, respectively. The GetHeight method returns the height of a Font object. The ToHfont and ToLogFont methods convert a Font object to a window handler and a GDI LOGFONT structure, respectively.
Property |
Description |
---|---|
Bold |
Returns true if the font is bold. |
FontFamily |
Every font belongs to a font family. This property returns the FontFamily object associated with a Font object. |
GdiCharSet |
Returns a string containing all characters. |
GdiVerticalFont |
Returns true if a font is derived from a GDI vertical font; otherwise returns false. |
Height |
Returns the height of a font. |
Italic |
Returns true if a font is italic. |
Name |
Returns the face name of a font. |
Size |
Returns the em size of a font in font design units. |
SizeInPoints |
Returns the size, in points, of a font. |
Strikeout |
Returns true if a font specifies a horizontal line through the font. |
Style |
Returns style information for a font, which is a type of FontStyle enumeration. |
Underline |
Returns true if a font is underlined. |
Unit |
Returns the unit of measure for a font. |
In the following example, you must import the GDI library by adding the following code at the beginning of your class before using any GDI fonts, because we will be using GetStockObject:
[System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")] private static extern IntPtr GetStockObject(int fnObj);
Listing 5.7 creates a font from a GDI handle and draws a string on the form. The FromHfont method creates a Font object from a GDI handle.
Listing 5.7 Using the FromHfont method
private void FromHfontMenu_Click(object sender, System.EventArgs e) { // Create the Graphics object Graphics g = this.CreateGraphics(); // Create a brush SolidBrush brush = new SolidBrush(Color.Red); // Get a handle IntPtr hFont = GetStockObject(0); // Create a font from the handle Font hfontFont = Font.FromHfont(hFont); // Draw text g.DrawString("GDI HFONT", hfontFont, brush, 20, 20); // Dispose of objects brush.Dispose(); hfontFont.Dispose(); g.Dispose(); }
Figure 5.12 shows the output from Listing 5.7.
Figure 5.12. Using the FromHFont method
5.3.7 Constructing a Font Object
A Font object belongs to the FontFamily class, so before we construct a Font object, we need to construct a FontFamily object. The following code snippet creates two FontFamily objects, belonging to the Verdana and Arial font families, respectively.
// Create font families FontFamily verdanaFamily = new FontFamily("Verdana"); FontFamily arialFamily = new FontFamily("Arial");
The Font class provides more than a dozen overloaded constructors, which allow an application to construct a Font object in different ways, either from string names of a font family and size or from a FontFamily object with font style and optional GraphicsUnit values.
The simplest way to create a Font object is to pass the font family name as the first argument and the point size as the second argument of the Font constructor. The following code snippet creates a Times New Roman 12-point font:
Font tnwFont = new Font("Times New Roman", 12);
The following code snippet creates three fonts in different styles belonging to the Verdana, Tahoma, and Arial font families, respectively:
// Create font families FontFamily verdanaFamily = new FontFamily("Verdana"); FontFamily arialFamily = new FontFamily("Arial"); // Construct Font objects Font verdanaFont = new Font( verdanaFamily, 14, FontStyle.Regular, GraphicsUnit.Pixel); Font tahomaFont = new Font( new FontFamily("Tahoma"), 10, FontStyle.Bold|FontStyle.Italic, GraphicsUnit.Pixel); Font arialFont = new Font(arialFamily, 16, FontStyle.Bold, GraphicsUnit.Point); Font tnwFont = new Font("Times New Roman", 12);
Note
As the code example here shows, you can use the FontStyle and GraphicsUnit enumerations to define the style and units of a font, respectively.
If you don't want to create and use a FontFamily object in constructing a font, you can pass the font family name and size directly when you create a new Font object. The following code snippet creates three fonts from the Verdana, Arial, and Tahoma font families, respectively, with different sizes and styles:
// Construct Font objects Font verdanaFont = new Font( "Verdana", 12); Font arialFont = new Font( arialFamily, 10); Font tahomaFont = new Font( "Arial", 14, FontStyle.Underline|FontStyle.Italic);
GDI+: The Next-Generation Graphics Interface
Your First GDI+ Application
The Graphics Class
Working with Brushes and Pens
Colors, Fonts, and Text
Rectangles and Regions
Working with Images
Advanced Imaging
Advanced 2D Graphics
Transformation
Printing
Developing GDI+ Web Applications
GDI+ Best Practices and Performance Techniques
GDI Interoperability
Miscellaneous GDI+ Examples
Appendix A. Exception Handling in .NET