Tuesday, October 20, 2009

14.2 Bitmap Fonts




< BACK  NEXT >

[oR]

14.2
BITMAP FONTS


Glyphs in a font may be represented using different methods. The simplest way is using a bitmap to represent the pixels making up each glyph. Such fonts are called bitmap fonts. Another way is to use straight lines to represent the outline of each glyph, which gives vector fonts. Most of the fonts we use in Windows today are TrueType fonts or OpenType fonts. These fonts use a much more sophisticated method to represent the outline of glyphs and control the rendering of these outlines. We will discuss bitmap fonts in this section, Vector fonts in Section 14.3, and TrueType fonts in Section 14.4.



Bitmap fonts have a long history in computer display. In the old DOS days, BIOS ROM contained several bitmap fonts for different display resolutions. When an application issues a software interrupt to display a character in graphics mode, BIOS fetches the glyph data and displays it in a specified position. For the initial Windows operating systems before Windows 3.1, bitmap fonts were the only font type supported. Even today, bitmap fonts are still used as stock fonts which are heavily employed in user inter face displays like menus, dialog boxes, and tool-tip messages, not to mention DOS boxes.



Even the latest Windows operating systems still use dozens of bitmap fonts. Different display resolutions use a different set of bitmap fonts to match the display resolution. For example, sserife.fon is MS Sans Serif font for 96-dpi display mode with 100% aspect ratio, while sseriff.fon is for 120-dpi display mode. When you switch display mode from small font (96-dpi) to large font (120-dpi), sseriff.fon gets enabled instead of sserife.fon. System font change affects the base units used in converting dialog box design-time coordinates to screen coordinates, so all your carefully crafted dialog boxes are messed up by the simple font change. Some bitmap fonts are so critical to system operation that they are marked as hidden files to avoid accidental deletion.



A bitmap font file usually has the .FON file extension. It uses the 16-bit NE executable file format initially used in 16-bit Windows. Within a FON file, a text string is embedded which describes the font characteristics. For example, the description for courf.fon is �FONTRES 100,120,120 : Courier 10,12,15 (8514/a res),� which contains font name, design aspect ratio (100), DPI (120x120), and point sizes supported (10, 12, 15).



For each point size supported by a bitmap font, there is one raster font resource, usually stored in a file with .FNT file extension. Multiple raster font resources can be added as a FONT type resource to the final bitmap font file. Platform SDK provides a FONTEDIT utility to modify an existing font resource file, with full source code.



Although old-fashioned, a bitmap font resource is still quite an interesting place to understand how fonts are designed and used. There are two versions of raster font resources, version 2.00 used for Windows 2.0 and version 3.00 originally designed for Windows 3.00. You may not believe that even Windows 2000 is using the version 2.00 raster font format. The fancy features provided by version 3.00 are well covered by TrueType fonts.



Each font resource starts with a fixed-size header, which contains version, size, copyright, resolution, character set, and font metrics information. For version 2.00 fonts, the Version field will be 0x200. For raster fonts, the LSB of Type is 1. Each font resource is designed for one normal resolution and a certain DPI resolution. Modern display monitors normally use square resolution�for example, 96 dpi by 96 dpi. A 10-point font for 96-dpi display will roughly be 13 (10*96/72) pixels in height. The bitmap font resource only supports one single-byte character set. It contains glyphs for all the characters within the range specified by FirstChar and LastChar. Each font resource defines a default char, which will be used to display characters not in the provided range. The BreakChar is the word break character.





typedef struct
{
WORD Version; // 0x200 for version 2.0, 0x300 for version 3.00
DWORD Size; // Size of whole resource
CHAR Copyright[60];
WORD Type; // Raster font if Type & 1 == 0
WORD Points; // Nominal point size
WORD VertRes; // Nominal vertical resolution
WORD HorizRes; // Nominal horizontal resolution
WORD Ascent;
WORD IntLeading;
WORD ExtLeading;
BYTE Italic;
BYTE Underline;
BYTE StrikeOut;
WORD Weight;
BYTE CharSet;
WORD PixWidth; // 0 for variable width
WORD PixHeight;
BYTE Family; // Pitch and family
WORD AvgWidth; // Width of character 'x'
WORD MaxWidth; // Maximum width
BYTE FirstChar; // First character defined in font
BYTE LastChar; // Last character defined in font
BYTE DefaultChar; // Sub. for out-of-range chars.
BYTE BreakChar; // Word break character
WORD WidthBytes; // No. bytes/row of bitmap
DWORD Device; // Offset to device name string
DWORD Face; // Offset to face name string
DWORD BitsPointer; // Loaded bitmap address
DWORD BitsOffset; // Bitmap offset
BYTE Reserved; // 1 byte, not used
} FontHeader20;


The character table, or rather glyph table, comes after the font resource header. For the version 2.00 raster font, the character table entry for each character in the supported range contains two 16-bit integers: one for the glyph width and one for the offset to the glyph. Now you can see the serious design limitation of the version 2.00 font resource: Each font resource is limited to 64 KB in size because of the 16-bit offset. The character table contains (LastChar-FirstChar+2) entries. The extra entry is guaranteed to be blank.





typedef struct
{
SHORT GIwidth;
SHORT GIoffset;
} GLYPHINFO_20;


Version 2.00 supports only monochrome glyphs. Although version 3.00 is designed to support 16-color, 256-color, or even true color glyphs, no such fonts are actually found to exist in the real world. For monochrome glyphs, each pixel only needs one bit. But the order of these bits in these glyphs is nothing like the bitmap formats we've encountered. The first byte of the glyph is the first 8 pixels of the first scan line, the second byte is the first 8 pixels of the second scan line, until the first 8-pixel column of the glyph is completed. This is followed by the second 8-pixel column, the third 8-pixel column, and so on, until the width of the glyph is fully covered. Such design was quite a common optimization technique to speed up character display.



Here is a routine to display a single glyph as a bitmap. The routine locates the GLYPHINFO table after the header, calculates the glyph index in the glyph table, and then converts the glyph to a monochrome DIB, which is then displayed using DIB function.





int CharOut(HDC hDC, int x, int y, int ch, FontHeader20 * pH,
int sx=1, int sy=1)
{
GLYPHINFO_20 * pGlyph = (GLYPHINFO_20 *) ((BYTE *)&pH->BitsOffset+5);

if ( (ch<pH->FirstChar) || (ch>pH->LastChar) )
ch = pH->DefaultChar;

ch -= pH->FirstChar;

int width = pGlyph[ch].GIwidth;
int height = pH->PixHeight;
struct { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[2]; } dib =
{
{ sizeof(BITMAPINFOHEADER), width, -height, 1, 1, BI_RGB },
{ { 0xFF, 0xFF, 0xFF, 0 }, { 0, 0, 0, 0 } }
};

int bpl = ( width + 31 ) / 32 * 4;
BYTE data[64/8*64]; // enough for 64x64
const BYTE * pPixel = (const BYTE *) pH + pGlyph[ch].GIoffset;

for (int i=0; i<(width+7)/8; i++)
for (int j=0; j<height; j++)
data[bpl * j + i] = * pPixel ++;

StretchDIBits(hDC, x, y, width * sx, height * sy, 0, 0, width, height,
data, (BITMAPINFO *) & dib, DIB_RGB_COLORS, SRCCOPY);

return width * sx;
}


If we can convert the font resource into GDI supported bitmaps, we can display characters ourselves without GDI's text function. Figure 14-10 shows all the glyphs in a raster font for 8-point and 10-point MS Serif font resource at 96 dpi.




Figure 14-10. Glyphs in a bitmap font.


Use the raster font as an example, we're seeing what a font really is. A raster font, as defined by the Windows version 2.00 font format, is a set of font resources designed at different point sizes; each font resource is a set of monochrome bitmap glyphs that are mapped one-to-one with a character in a single-byte character. The raster font supports a simple mapping from a character in the character set to glyph indexes in a glyph table through a range of supported characters. The glyphs for the characters can be easily converted to GDI-supported bitmap formats and displayed on a graphics device. Bitmap fonts also provide extra simple text metrics information.



Bitmap fonts are great for displaying small characters on the screen, both in terms of quality and performance, which is the main reason they still survive today. For different point sizes, bitmap fonts have to provide different sets of font resources. For example, a bitmap font used in Windows today normally provides 8-, 10-, 12-, 14-, 18-, and 24-point font resources. For other point sizes, or for a device with different resolution, glyphs need to be scaled to the required size. Bitmap scaling is always a problem, especially upscaling that requires new pixels to be generated. Figure 14-11 illustrates the result of scaling a glyph from a 24-point bitmap font, using a simple duplication method.




Figure 14-11. Scaling a raster font glyph.


Figure 14-11 shows the result of integer ratio scaling in both directions, where each pixel in the glyph is duplicated the same number of times. The rough edge is clearly visible. If the scaling is a noninteger ratio, the character displayed can have strokes with uneven thickness, as some pixels are scaled n times and others n + 1 times. Clearly, the scaling raster fonts does not provide good enough display/print quality; we have to find other ways to encode fonts for continuous and smooth scaling.






< BACK  NEXT >





No comments:

Post a Comment