ۥ-x@ -:EV8<DeDeeDeDeDeDeDsDfDDDDD DD EBKEKEaEaEaEaEaEaEaEcEcEcEcEcEcEE4E1EeDEECharles Petzold 63 E. 9th St. -- Apt. 10-N New York, NY 10003 212-260-3698 Metafiles, Mapping Modes, and Transforms In the olden (and largely academic) days of computer graphics theory, it was assumed that display surfaces were continuously addressable. There were no such nuisances as pixels to impose limitations on the coordinaate addressability of the device. Indeed, early video displays were vector devices rather than the raster devices used today. The electron beam could be moved in any type of pattern instead of being confined to sweeps of horizontal lines. (There was a good reason for this: Raster displays require more memory than vector displays, and memory was quite expensive back then.) Nowadays, the only continuously-addressable graphics display device commonly used is the pen plotter, and those are quickly becoming obsolete with the widespread availability of inexpensive color laser printers. The early theoreticians of computer graphics often came from a background in mathematics, so they tended to think of the display as a hardware implementation of a rectangular (or Cartesian) coordinate system. The origin would be in the center of the display and coordinates would extend for (say) 1000 units horizontally left and right, and vertically up and down. Of course, nothing prevented you from using fractional coordinates. These days, real-world displays are almost always raster devices. Both video displays and laser printers have a discrete pixel resolution that constrains the addressability. To Map or Not to Map -------------------- Windows is primarily a pixel-based graphics system. And because there is no such thing as a fractional pixel, that allowed Windows to be an integer-based system. For programmers who preferred to work in arbitrary units, or the metric units of inches or millimeters, the early designers of the Windows Graphical Device Interface (GDI) introduced the concept of the mapping mode. The mapping mode is simply a coordinate transform that involves translation and scaling. For example, when you select the mapping mode of MM_LOENGLISH (which lets you draw in units of 0.01 inches), GDI sets up a scaling factor that is effectively the number of pixels in 0.01 inches for the particular device. (This is expressed as a ratio of two integers to avoid floating point calculations.) Certainly using mapping modes is convenient in some cases. But, as I've often demonstrated (and as recently as the last issue), it is possible to work in units of inches or millimeters without using mapping modes. The GetDeviceCaps function gives you all the information you need to properly do your own scaling. Although I'm obviously not privy to the source code of large graphical applications, I suspect that most programmers of those applications tend to avoid the mapping modes or use them sparingly. After all, letting GDI do coordinate scaling involves some relinquishing of control. Many programmers don't like to do that. Also, once a programmer encounters a problem with using mapping modes, the ease-of-use issue is irrelevant. One such problem involves ScrollDC, which scrolls an area of the device context. The ScrollDC function requires device units (pixels). If you're using a mapping mode when drawing, you must use the LPtoDP function to convert the logical units of the scroll area to device units in preparation for calling ScrollDC. Sometimes this results in annoying off-by-one rounding errors. I'm not advocating that you not use mapping modes, of course, or (worse) avoid learning about them because you believe you'll never use them. A good graphics programmer knows the entire graphics system -- and particularly how various functions interact -- and uses whatever is appropriate for the job. Metafiles, Inches, and Millimeters ---------------------------------- In the past several columns, I've been discussing the enhanced metafile format as implemented under Windows NT. In the last issue, I showed you how to encode the image of a 6-inch ruler in a metafile and then display it in its proper size on both the video display and the printer. Both steps of this job involved working with dimensions other than pixels, although I managed to avoid using mapping modes. When creating the metafile, it was necessary to use GetDeviceCaps to find the number of pixels per inch based on the video display. Thus, the ruler could be drawn in the metafile device context using pixels. As we've seen, GDI encodes two pieces of important information in the header section of the enhanced metafile. These are the rectangular bounding box of the image in pixels, and also in units of 0.01 millimeters. The relationship between these two rectangles is based on the resolution of the reference device context, which by default is the video display. To display the metafile image in its proper size, you use the rectangle stored in the header that provides the bounding box in units of 0.01 millimeters. Based on the resolution of the device on which you're drawing the metafile, you convert the dimensions of the image to pixels. This provides the information you need to set up a destination rectangle for the PlayEnhMetaFile call. The metafile image is displayed within that destination rectangle I avoided using mapping modes in last issue's sample programs because I wanted as little as possible happening behind the scenes. But the question naturally arises: Can we use mapping modes to simplify the creation and display of metafiles? Well, let's try. Embedded SetMapMode Functions ----------------------------- Whend you call SetMapMode using a metafile device context, the function is encoded in the metafile just like any other GDI function. This is demonstrated in the EMF12 program shown in Figures 1 and 2. [ Figure 1. The EMF12.MAK file facilitates compilation and linking of the EMF12 program. Figure 2. The EMF12.C file encodes a ruler into a metafile using a mapping mode. ] You'll need the EMF files from the last issue to compile and link this program. If you have Windows NT and the Win32 Software Development Kit installed, you can create EMF12.EXE by running: NMAKE EMF12.MAK from a Windows NT command line. Or you can download all the sources files and the executable from ZiffNet. The CreateRoutine function in EMF12 is simpler than the one in EMF9 (our original ruler-metafile program) because it does not need to call GetDeviceCaps to determine the resolution of the video display in dots per inch. Instead, EMF12 calls SetMapMode to set the mapping mode to MM_LOENGLISH, where logical units are equal to 0.01 inches. Thus, the dimensions of the ruler are 600 units by 100 units, and these numbers are passed to the DrawRuler function. The DrawRuler function in EMF12 is the same as the one in EMF9, except for the MoveToEx and LineTo calls that draw the tick marks of the ruler. When drawing in units of pixels (the default MM_TEXT mapping mode), units on the vertical axis increase going down the screen. For the MM_LOENGLISH mapping mode (and the other metrical mapping modes), they increase going up. That required a change to this code. The PaintRoutine function in EMF12 is basically the same as the one in last issue's EMF10, which was the version of the program that successfully displayed the ruler in its correct dimensions on both the video display and the printer. The only difference is that EMF12 uses the EMF12.EMF file, whereas EMF10 used the EMF9.EMF file created by EMF9. In the header record of EMF9.EMF, the dimensions were recorded as 402 pixels wide and 67 pixels high, and 150.75 millimeters wide and 25.13 millimeters high. Of course, there are 25.4 millimeters to the inch, so the dimensions are not precise. This results from the program rounding the VGA pixel resolution to 67 dots per inch. I mentioned earlier that the dimensions of the image are recorded as rectangles. For EMF9, the left and top fields of the RECT structure are zero, and the figures in the paragraph above indicate the right and bottom fields. In EMF12.EMF the RECT structure fields for the pixel dimensions are recorded as (0, -67, 406, 0), and the millimeter dimensions are (0, -25.49, 152.25, 0). This accounts for units of y increasing going up. Also note that GDI managed to be a bit more accurate in calculating the dimensions of the ruler. Because EMF12 calculates the horizontal and vertical dimensions of the image by subtracting the left field from the right field, and the top field from the bottom field, the calculation yields the same result as EMF10. The image displayed by EMF12 is basically the same as EMF10. So, we see here how embedding a SetMapMode call into a metafile can simplify the metafile creation and doesn't affect at all the mechanics of playing of the metafile in its correct size. Now let's see what other games we can play. Mapping and Playing ------------------- Calculating the destination rectangle in EMF12 involves some calls to GetDeviceCaps. Our second goal is to eliminate those and use a mapping mode instead. GDI treats the coordinates of the destination rectangle as logical coordinates. Using the MM_HIMETRIC mode seems like a good candidate for these coordinates, because that makes logical units 0.01 millimeters, the same units used for the bounding rectangle in the enhanced metafile header. The EMF13 program shown in Figures 3 and 4 restores the original metafile-creation logic as originally presented in last issue's EMF9, but uses the MM_HIMETRIC mapping mode to display the metafile. [ Figure 3. The EMF13.MAK file facilitates compilation and linking of the EMF13 program. Figure 4. The EMF13.C file displays a ruler metafile using a mapping mode. ] The PaintRoutine function in EMF13 first sets the mapping mode to MM_HIMETRIC. As with the other metric modes, values of y increase going up the screen. However, the origin is still at the upper-left corner, which means that y-coordinates within the client area are negative. To correct this oddity, the program calls SetViewportOrgEx to set the origin to the lower-left corner. The device point (cxArea,0) is at the upper-right corner of the screen. Passing that point to the DPtoLP ("device point to logical point") function gives us the size of the client area in 0.01 millimeters. The program then loads the metafile, gets the header, and finds the dimensions of the metafile in 0.01 millimeters. The destination rectangle centered in the middle of the client area is then easy to calculate. Combining the Effects --------------------- Now we've seen how we can use a mapping mode when creating the metafile, and also for displaying it. Can we do both? When I first considered this, my immediate instinct was "No way!" In effect, the program would be setting the mapping mode to MM_HIMETRIC when playing the metafile, but the first call in the metafile changes the mapping mode to MM_LOENGLISH, so what does that do to the destination rectangle? It turns out to work, as EMF14 (shown in Figures 5 and 6) demonstrates. [ Figure 5. The EMF14.MAK file facilitates compilation and linking of the EMF14 program. Figure 6. The EMF14.C file displays the ruler metafile from EMF12 using a mapping mode. ] In the EMF14 program, it's not necessary to create the ruler metafile using a mapping mode because it's already been created by EMF12. EMF14 simply loads that one and uses a mapping mode to calculate the destination rectangle, just like EMF13. Now we can establish a couple principles: When the metafile is created, GDI uses any embedded changes to the mapping mode to calculate the size of the metafile image in pixels and millimeters. The size of the image is stored in the metafile header. When the metafile is played, GDI establishes the physical location of the destination rectangle based on the mapping mode in effect at the time of the PlayEnhMetaFile call. Nothing in the metafile can change that location. Metafiles and the World Transform --------------------------------- The enhanced metafile format is new with Windows NT, but so are a few other graphics features, such as the world transform. Logical points in NT are modified first by the world transform and then by the mapping mode (or, more accurately, the window and viewport origins and extents) to yield device points. This implies that we can define a world transform in the destination device context and display the metafile image in a skewed or rotated rectangle. This is demonstrated in EMF15, shown in Figures 7 and 8. [ Figure 7. The EMF15.MAK file facilitates compilation and linking of the EMF15 program. Figure 8. The EMF15.C file displays the ruler metafile from EMF12 with rotation. ] To simplify the world transform factors, I've set the origin to the center of the client area. This also eliminates the need for the DPtoLP call, because the destination rectangle coordinates are positive and negative offsets (based on the size of the ruler) from the origin. The world transform matrix rotates the destination rectangle 45 degrees counter-clockwise around the origin. The results are shown in Figure 9. [ Figure 9. The rotated ruler displayed by the EMF15 program. [ EN19FG09.PCX ] ] Any mapping mode or world transform you set before the PlayEnhMetaFile call remains in effect after the call has completed. You'd probably expect such behavior. But how do other device context attributes affect the metafile? For example, if you create a red pen and select it into the device context before calling PlayEnhMetaFile, will the ruler be drawn in red? The answer is No. PlayEnhMetaFile effectively saves the state of the device context, sets the attributes to default values (which may be modified by commands within the metafile), and then restores the device context state after completion. The only reason that the mapping mode and world transform affects the metafile is because GDI interprets the destination rectangle in the logical coordinates defined at the time PlayEnhMetaFile is called. And with that, let's conclude our exploration of the Windows NT enhanced metafile format and move on to new pastures. Environments, Volume 13, Number 19 Page page1 v@ay be modified by commands within the metafile), and then restores the device context state after completion. The only reason that the mapping mode and world transform affects the metafile is because GDI interprets the destination rectangle in the logical coordinates defined at the time PlayEnhMetaFile is called. And with that, let's conclude our exploration of the Windows NT enhanced metafile format and move on to new pastures. Environments, Volume 13, Number 19 Page 9::::::::: *,? A  Q S =?oq(*[]QSegrtxz*,02uwCE?A q!s!##! !!!! !!!!!M#$$$$$$$&&e'g'k'm'''(((())r*t*K+M+d+{+}+++-!-j-l-p-r---).+./.1.'/)/1 1-1P1R122Y3[3_3a333444455556 66 6$6&677Y9[9999 : :!  !!!!!!!!P :::::!! F 8:b x")18]y6:@:# :: !BTimes New Roman Symbol&Arial5Courier New 6Courier*/1@!T8T8T8T8"h=eA1Charles PetzoldCharles Petzold