INF: Displaying on the Screen What Will Print

ID Number: Q22553

2.x 3.00

WINDOWS

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.

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:

1. "Pocket Pal -- A Graphic Arts Production Handbook" from

International Paper Company; discusses issues related to type and

typesetting.

2. "Bookmaking" by Marsha Lee; discusses issues related specifically

to making books.

3. "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:

1. Printer manufacturers produce excellent fonts on their printers.

Use printer fonts as much as possible.

2. GDI must provide some fonts for use with font-deficient display

drivers.

3. 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:

1. Windows Notepad application (does a less-than-ideal job)

2. Windows Write application (does better; however, the point at which

various screen lines word wrap with different fonts is jagged)

3. 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:

1. 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.

2. 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)

3. 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.

4. 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.

5. 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.

6. 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.

7. 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.

8. 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.

9. 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

Additional reference words: 3.00 3.0