Displaying on the Screen What Will Print

ID: Q22553


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:

  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:

    1. Take no special action. Put the text on the screen based on screen DC text metrics. With this method, only minimal matching is obtained.


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


    3. 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 query words: 3.00 3.10 3.50 4.00 win16sdk


Keywords          : 
Version           : 
Platform          : 
Issue type        : 

Last Reviewed: March 3, 1999