The information in this article applies to:
SUMMARY
It is possible for an application to closely simulate on the screen
how an block of text will appear when printed. This article provides
some references and techniques to accomplish this goal.
NOTE: WYSIWYG functionality can be attained in Windows 3.1 by using
TrueType fonts. The following information should be used with non-TrueType
fonts.
MORE INFORMATION
To create a what-you-see-is-what-you-get (WYSIWYG) screen image, the
application must combine the services of the Windows graphics device
interface (GDI), the printer, the display, and fonts. The following
three references provide information that may be helpful:
- "Pocket Pal -- A Graphic Arts Production Handbook" from
International Paper Company; discusses issues related to type and
typesetting.
- "Bookmaking" by Marsha Lee; discusses issues related specifically
to making books.
- "Phototypesetting, A Design Manual" by James Craig.
These books contain information about type, fonts, and stringing
characters together to make text. The following are three points to
remember:
- Printer manufacturers produce excellent fonts on their printers.
Use printer fonts as much as possible.
- GDI must provide some fonts for use with font-deficient display
drivers.
- Displays (even high-end ones) have much lower resolution than
printers.
The best displays attached to microcomputers are approximately 120
dots-per-inch (dpi), while the typical laser printer is 300 dpi. To
produce the same size image (for example, a 9-point capital A), the
printer will illuminate/paint more of its pixels than will the screen.
In particular, the printer will more closely match the requested size
than the display. This leads to integer round-off errors.
Most graphics output devices are raster devices. Due to integer
round-off errors associated with sampling the ideal "A" for different
device resolutions, the origin of characters and words and the ends of
lines on the display will seldom be the same as on a printer. For
example, using a 75-dpi display and 300-dpi printer, the display might
choose a 6 pixel-width for the character "A", while the printer might
choose a 25 or 23 pixel-width for that same character. This mismatch
necessitates adjusting the text on the display to match the output on
the printer.
GDI provides various approaches to find the information needed to
perform the adjustments. The following applications perform this task
with increasing sophistication:
- Windows Notepad application (does a less-than-ideal job)
- Windows Write application (does better; however, the point at which
various screen lines word wrap with different fonts is jagged)
- Word for Windows (does an excellent job of handling text)
The first two applications are included with the Windows operating
environment.
When Windows starts up, GDI asks each device whether it can support
any fonts. For devices that provide some intrinsic (driver-based)
fonts, GDI enumerates the available fonts and creates a table that
describes them. When an application requests a font from GDI (using
the CreateFont and SelectObject functions), GDI selects the font in
its table that most closely matches the requested font. If no device
font matches well, GDI will attempt to use one of its own fonts.
Ideally, the requested font will be available for all devices. More
realistically, GDI provides a similar font, within the limits of the
device capabilities.
The best way to imitate the appearance of printer fonts on a display
is to assume that the printer has more fonts and greater resolution
than the display. The following nine steps describe one way to
implement a WYSIWYG display:
- Open a device context (DC) and enumerate the fonts available on the
printer. Use information from the GetDeviceCaps function with the
TEXTCAPS parameter to determine how the device can alter the
appearance of the fonts it provides. Together, the EnumFonts and
GetDeviceCaps functions will allow the application to determine
which fonts the device and GDI can provide. The text capabilities
of the device serve as a filter in the enumeration process.
- Provide a user interface in the application to allow the user to
choose one of the fonts (this will result in "printer-centered
WYSIWYG"). If appropriate, provide a method to choose between sizes
and other attributes (bold, italic, and so forth). Fonts are most
commonly selected by point size. One point equals 1/72 of an inch.
Enumerating fonts returns LOGFONT and TEXTMETRIC structures. The
quantities in these structures are in logical units that depend on
the current mapping mode. Assuming that MM_TEXT (the default
mapping mode) is selected, one logical unit equals one device unit
(pixel, or pel). Font height and internal leading define the point
size of the font as follows:
72 * (tmHeight - tmInternalLeading)
point_size = -----------------------------------
GetDeviceCaps(hDC, LOGPIXELSY)
- Create a LOGFONT structure for the selected font. To ensure
successful selection of that font into the printer DC, the
lfHeight, lfWeight, and lfFacename fields must be specified. Weight
and face name can be copied directly from the LOGFONT structure
that was returned during the enumeration. The height should be
computed using the following formula:
lfHeight = -(point_size * GetDeviceCaps(hDC, LOGPIXELSY) / 72)
In normal situations, set lfWidth to zero.
- Once a font has been chosen, select it into the printer DC. Use
GetTextMetrics and GetTextFace to verify the selection. If the
steps above are followed, the process should fail only when very
little memory is available in the system.
- Create a device context for the display. Use the equation listed in
step 2 above to compute the logical height for the font to be
selected into the screen DC. Use CreateFont and SelectObject to
select this logical font into the display DC, and use
GetTextMetrics and GetTextFace to retrieve a TEXTMETRIC data
structure and the face name for the selected font.
- The font selected for the display is generally not the same as the
font selected for the printer. To achieve WYSIWYG and the highest
possible quality of the printed output, it is best to perform all
page layout computations based on the metrics obtained from the
printer DC, and force the output on the screen to match the printer
output as closely as possible. This process generally causes some
degradation of quality. It is assumed in the remainder of this
discussion that text quality is most important.
- Check whether either device supports the GDI escape codes that
enhance the usability of fonts. One escape code, for example,
returns the width table for proportionally spaced fonts. These
escapes are listed in chapter 12 of the "Microsoft Windows Software
Development Kit Reference, Volume 2." Use the escape code
QUERYESCSUPPORT to discover whether a device supports a particular
escape code. The width tables provide data to determine the
physical extent of character strings to be sent to the printer and
how to match that extent on the display.
- If the devices do not support those GDI escapes, select the desired
font into a printer DC and use the GetTextExtent function to get
the extent a string will occupy when printed.
- With the methods outlined in steps 7 and 8, the dimensions of any
string can be computed for the printer device. This information is
used to compute page breaks and line breaks. Once the placement and
extent of a string of text have been determined on the printed
page, it is possible to create a scaled image on the screen. There
are three methods of forcing a match between printer and screen:
a. Take no special action. Put the text on the screen based on
screen DC text metrics. With this method, only minimal matching
is obtained.
b. Use either the GetTextExtent function or the combination of the
GetCharWidths, SetTextJustification, and SetTextCharacterExtra
functions to create the same line breaks and justification on
the screen as on the printed page. This method uses white space
(usually the space character) to stretch or shrink a string of
text (action of SetTextJustification) and adds a constant value
to the width of every character in the font (action of
SetTextCharExtra). This method achieves reasonable WYSIWYG.
c. Use the ExtTextOut function and pass a width array to achieve
the exact placement of each and every character in the string.
This method provides the highest degree of WYSIWYG; however, it
also requires character placement algorithms that do not degrade
the speed of text output too much.
The following functions related to this article are documented in
chapter 4 of the "Microsoft Windows Software Development Kit
Reference, Volume 1:"
CreateFont
CreateFontIndirect
EnumFonts
Escape
GetCharWidths
GetDeviceCaps
GetTextExtent
GetTextFace
GetTextMetrics
SelectObject
SetMappingMode
SetViewportExtent
SetViewportOrigin
SetWindowExtent
SetWindowOrigin
The LOGFONT and TEXTMETRIC data structures are documented in Chapter 7
of the SDK reference, volume 2.
The following device escape functions are documented in Chapter 12 of
the SDK reference, volume 2:
ENABLEPAIRKERNING
ENABLERELATIVEWIDTHS
EXTTEXTOUT
GETEXTENDEDTEXTMETRICS
GETEXTENTTABLE
GETPAIRKERNTABLE
GETTRACKKERNTABLE
QUERYESCSUPPORT
SETKERNTRACK