|
|
1.1 root 1:
2:
3:
4:
5:
6:
7: The Presentation Manager Vector Fonts
8: by Charles Petzold
9:
10:
11:
12: Let's begin with a question: What graphics programming
13: language stores fonts as a lines and curves (rather than
14: bitmaps), and thus allows fonts to be arbitrarily stretched,
15: rotated, outlined, filled with different patterns, or even
16: used as clipping areas?
17:
18: One answer is obviously PostScript, Adobe Systems' page
19: composition language implemented on many high-end laser
20: printers (beginning with the Apple LaserWriter) and Allied
21: Corporation's Linotronic phototypesetters. Over the past few
22: years, PostScript has become the language of choice for
23: computer manipulation of fonts and text.
24:
25: But an equally valid answer is GPI -- the Graphics
26: Programming Interface component of the OS/2 Presentation
27: Manager. As we'll see, GPI has facilities to do virtually
28: everything with fonts that you can do with PostScript.
29:
30:
31: The Trouble With Text
32:
33: The display of text is always the most problematic part of a
34: graphics programming system. Unlike lines and polygons
35: (which are merely mathematical constructs), text is rooted
36: in a long tradition of aesthetic typography. In any computer
37: graphics system, the goal must always be to display text
38: that is as pleasing and as easy to read as a well-printed
39: book.
40:
41: Yet, most computer output devices (such as video displays
42: and printers) are digital media. The subtly shaped and
43: rounded characters that comprise traditional fonts must be
44: broken down into discrete pixels for storage and then
45: reassembled on the output device. This often causes
46: distortions in the appearance of the text.
47:
48: But one major advantage of using a computer for this job is
49: versatility: We can use a wide variety of fonts in various
50: sizes and characteristics, and modify these fonts for
51: display. The extent to which we can modify fonts is
52: dependent on the way in which the fonts are stored in
53: memory.
54:
55:
56: Images and Vectors
57:
58: A font is generally stored in computer (or printer) memory
59: in one of two very different ways:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73: First, a font can be stored as an "image" or "bitmap." Each
74: character of the font is simply a rectanglar array of bits.
75: The 0 bits generally correspond to the background around the
76: character and the 1 bits correspond to the character itself.
77:
78: Secondly, a font can be stored in a "vector" or "outline"
79: format. Each character is defined as a series of lines and
80: curves that enclose areas. The character is displayed by
81: drawing the outline on the output device and filling the
82: enclosed areas.
83:
84: Image and vector fonts have distinct advantages and
85: disadvantages. Image font are always created for specific
86: font sizes and specific device resolutions. The size of a
87: particular image font cannot easily be changed. (For
88: example, enlarging an image font by doubling the rows and
89: columns of pixels often emphasizes the jaggedness of the
90: characters.) Also, image fonts cannot be rotated except
91: possibly by 90 degree increments.
92:
93: Vector fonts are much more malleable. Because they are
94: defined as a series of lines and curves, vector fonts can be
95: stretched or compressed to any size and can be rotated to
96: any angle. Vector fonts are not tied to a particular output
97: device resolution.
98:
99: In general, however, image fonts are more legible that
100: vector fonts. Various techniques are used to design image
101: fonts so they fool the eye into thinking the characters are
102: smoother than they actually are. Vector fonts --
103: particularly when displayed on low resolution devices and
104: scaled to small font sizes -- can be adjusted only by
105: mathematical algorithms, which currently are less capable
106: than human font designers. Another advantage of image fonts
107: is performance: Vector fonts usually require much more
108: processing time to draw each character.
109:
110: Most conventional laser printers store fonts as images,
111: either within the printer or in font cartridges. The printer
112: is restricted to specific font sizes and the characters
113: cannot be arbitrarily rotated. Much more versatile are the
114: fonts stored in PostScript-based printers. These fonts are
115: stored as vectors. PostScript fonts can be stretched or
116: compressed to any size, they can be arbitrarily rotated,
117: filled with various patterns, and used for clipping.
118:
119:
120: The GPI Fonts
121:
122: The Graphics Programming Interface (GPI) of the OS/2
123: Presentation Manager can, of course, take advantage of fonts
124: that are stored in and supported by output devices such as
125: laser printers.
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139: But GPI also includes its own support of both image and
140: vector fonts. The image fonts are expected, of course,
141: because they are particularly suited for low resolution
142: video displays and dot matrix printers. Image fonts are an
143: important part of most graphics programming systems (such as
144: Microsoft Windows GDI).
145:
146: The addition of vector fonts in GPI is a real treat. GPI can
147: use these vector fonts with any output device. Thus, various
148: font techniques that previously have been restricted to
149: PostScript printers are now possible with other laser
150: printers and even the video display.
151:
152: This article shows you how to work with vector fonts in GPI
153: and demonstrates many PostScript-like techniques. Quite
154: simply, the font support in GPI is nearly as strong as that
155: in PostScript. However, GPI has a serious deficiency that
156: I'll discuss at the end of this article.
157:
158: OS/2 1.1 is shipped with three resource-only dyanamic link
159: libraries with a .FON extension. These are font files, and
160: the contents are shown in Figure 1.
161:
162: In addition, the video display device driver (DISPLAY.DLL)
163: and printer device drivers may also contain fonts designed
164: specifically for the device. For example, the default
165: "System Proportional" font is stored in DISPLAY.DLL.
166:
167: Important: If you want to use any of the fonts in the .FON
168: files, you must install the fonts from the Presentation
169: Manager Control Panel program. It is only necessary to
170: install one font from each of the three files, and you only
171: need do this once.
172:
173: Each font has a face name. This is shown in quotation marks
174: in Figure 1. Each of the image fonts is available in
175: several point sizes and for several output devices: the CGA,
176: EGA, VGA (and 8514/A), and IBM Proprinter. GPI can syntesize
177: variations of these fonts, such as italic or boldfaced
178: versions.
179:
180: Vector fonts, however, need not be designed for a particular
181: output device and point size because they can be arbitrary
182: scaled. You'll note that italic and boldface versions of the
183: vector fonts are also included.
184:
185: The vector fonts in GPI are equivalent to the Courier,
186: Helvetica, and Times fonts included in most PostScript
187: printers. However, because Helvetica and Times are
188: registered trademarks, these names are not used to identify
189: the vector fonts in GPI.
190:
191: A little exploration of the font files will reveal that
192: vector fonts are encoded as a series of GPI drawing orders.
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205: When drawing text with these fonts, GPI translates the
206: drawing orders into GPI functions, usually GpiPolyLine to
207: draw straight lines and GpiPolyFilletSharp to draw curves.
208:
209:
210: The VECTFONT Program
211:
212: The VECTFONT program demonstrates the use GPI vector fonts.
213: For purposes of clarity, I've divided the program into
214: several modules.
215:
216: The VECTFONT "Display" menu lists 16 options. The first
217: option (to display nothing) is the default. The other 15
218: options correspond to routines in the VF01.C through VF15.C
219: files (described below). The VF00.C file contains some
220: "helper" functions used by the routines in VF01.C through
221: VF15.C.
222:
223: VECTFONT creates a micro presentation space during the
224: WM_CREATE message using page units of PU_TWIPS. ("Twips" is
225: fabricated word standing for "20th of a point." A printer's
226: point size is 1/72nd inch, so page units correspond to
227: 1/1440 inch.) VECTFONT then modifies the page viewport
228: rectangle so that a page unit corresponds to 1 point, which
229: (as you may know) is the default coordinate system in
230: PostScript.
231:
232: Although VECTFONT displays output to the screen, vector
233: fonts are obviously more suited for laser printers. As you
234: will see, the appearance of the fonts -- even at 24 point
235: sizes -- is not nearly as good as the image fonts.
236:
237: You'll also notice that several of the demonstration
238: routines in VECTFONT requires a few seconds to run. For
239: anything other than a demonstration program, you'd probably
240: want to use a second thread of execution so as to not hold
241: up message processing.
242:
243:
244: Selecting an Outline Font
245:
246: To use an outline font in a Presentation Manager program,
247: you must first create a "logical font" and then select the
248: font into your presentation space.
249:
250: The GpiCreateLogFont function creates a logical font and
251: associates the font with a local ID (a number between 1L and
252: 254L that you select). This function requires a pointer to a
253: structure of type FATTRS ("font attributes") that specifies
254: the attributes of the font you want.
255:
256: To create a vector font, most of the fields in this
257: structure can be set to zero. The most important fields are
258: szFacename (which is set to the face name of the font) and
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271: fsFontUse, which is set to the constant identifiers
272: FATTR_FONTUSE_OUTLINE and FATTR_FONTUSE_TRANSFORMABLE,
273: combined with the C bitwise OR operator.
274:
275: You may prefer using the CreateVectorFont function in VF00.C
276: for creating a vector font. The VF00.C file contains several
277: other helpful functions that are used by the demonstration
278: routines in VF01.C through VF15.C.
279:
280: The CreateVectorFont function requires only the presentation
281: space handle, the local ID, and the face name:
282:
283:
284: CreateVectorFont(hps, lcid,
285: szFacename);
286:
287:
288: After you create a logical font (using either
289: GpiCreateLogFont or CreateVectorFont), you can select the
290: font into the presentation space:
291:
292:
293: GpiSetCharSet(hps, lcid);
294:
295:
296: The lcid parameter is the local ID for the font. After the
297: font is selected in the presentation space, you can alter
298: the attributes of the font with various functions described
299: below, obtain information about the font by calling
300: GpiQueryFontMetrics, GpiQueryWidthTable, and
301: GpiQueryTextBox, and you can use the font for text output
302: with one of the text functions such as GpiCharStringAt.
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336:
337: When you no longer need the font, you select the default
338: font back into the presentation space:
339:
340:
341: GpiSetCharSet(
342: hps,
343: LCID_DEFAULT);
344:
345:
346: and then delete the local ID associated with the font:
347:
348:
349: GpiDeleteSetId(hps, lcid);
350:
351:
352: In VECTFONT, I always use the identifier LCID_MYFONT for the
353: local ID. This is defined in VECTFONT.H as 1L.
354:
355:
356: Scaling to a Point Size
357:
358: When you call GpiSetCharSet to select a vector font into the
359: prsentation space, the initial width and height of the font
360: are based on the GPI "character box," which defines a
361: character width and height in page units. The default
362: character box is based on the size of the default system
363: font. You can change the character box size by calling
364: GpiSetCharBox.
365:
366: Very important: To get a correctly proportioned vector font,
367: it is necessary to change the character box size. Do not use
368: the default Generally you set the height of the character
369: box to the desired height of the font. If you want the a
370: vector font to have a normal width, you set the width of the
371: character box equal to the height. For a skinnier font, set
372: the width of the character box less than the height; for a
373: fatter font, set the width greater than the height.
374:
375: If you're working in page units of PU_PELS, you must also
376: adjust the character box dimensions to account for
377: differences in horizontal and vertical resolution of the
378: output device. For this reason, it's much easier to work
379: with vector fonts if you use one of the metric page units
380: (PU_LOENGLISH, PU_HIENGLISH, PU_LOMETRIC, PU_HIMETRIC, or
381: PU_TWIPS). With these page units, horizontal and vertical
382: page units are the same.
383:
384: For example, suppose you're using page units of PU_TWIPS.
385: This means that one page unit is equal to 1/20 of a point or
386: 1/1440 inch. After selecting a vector font into the
387: presentation space, you want to scale the font to 24 points.
388: You first define a structure of type SIZEF:
389:
390:
391:
392:
393:
394:
395:
396:
397:
398:
399:
400:
401:
402:
403: SIZEF sizfx;
404:
405:
406: The two fields of this structure are named cx and cy and are
407: interpreted as 32-bit FIXED numbers, that is, the high 16-
408: bits are interpreted as an integer, and the low 16-bits are
409: interpreted as a fraction.
410:
411: If you want to scale the vector font to a 24 point height,
412: you can use the MAKEFIXED macro to set to the fields of the
413: structure like this:
414:
415:
416: sizfx.cx = MAKEFIXED(
417: 24 * 20, 0);
418: sizfx.cy = MAKEFIXED(
419: 24 * 20, 0);
420:
421:
422: Multiplying by 20 is necessary to convert the point size you
423: want to twips. Then call GpiSetCharBox:
424:
425:
426: GpiSetCharBox(hps, &sizfx);
427:
428:
429: After setting the character box, any character or text
430: dimensions you obtain from GpiQueryFontMetrics,
431: GpiQueryTextBox, and GpiQueryWidthTable will reflect the new
432: font size.
433:
434: The ScaleVectorFont routine in VF00.C can help in scaling a
435: vector font to a desired point size. The function will work
436: with any page units, even PU_PELS. The second and third
437: parameters to ScaleVectorFont specify a point size in units
438: of 0.1 points. (For example, use 240 for a 24-point size.)
439: If you want a normally proportioned vector font, set the
440: third parameter to ScaleVectorFont equal to the second
441: parameter.
442:
443: The VF01.C file shows how the functions discussed so far can
444: be used to display all the available vector fonts in 24
445: point sizes. You can run the function in VF01.C by selecting
446: the "24 Point Fonts" option from the VECTFONT "Display"
447: menu.
448:
449:
450: Arbitrary Stretching
451:
452: Besides scaling the vector font to a specific point size,
453: you can also scale vector fonts to fit within an arbitrary
454: rectangle. For example, you may want to scale a short text
455: string to fill the client window.
456:
457:
458:
459:
460:
461:
462:
463:
464:
465:
466:
467:
468:
469: The function shown in VF02.C shows how this is done. You can
470: run this function by selecting "Stretched Font" from
471: VECTFONT's menu. The function in VF02.C displays the word
472: "Hello!" in the "Tms Rmn Italic" font stretched to the size
473: of the client window.
474:
475: The ScaleFontToBox function in VF00.C helps out with this
476: job. This function first calls GpiQueryTextBox to obtain the
477: coordinates of a parallelogram that encompasses the text
478: string. The character box is then scaled based on the size
479: of this text box and the rectangle to which the font must be
480: stretched. The QueryStartPointInTextBox function in VF00.C
481: determines the starting point of the text string (that is,
482: the point at the baseline of the left side of the first
483: character) within this rectangle. This point is used in the
484: GpiCharStringAt function to display the text.
485:
486:
487: Mirror Images
488:
489: Besides scaling the font to a particular size, the character
490: box can also flip the characters around the horizontal or
491: vertical axis.
492:
493: If the character box height (the cy field of the SIZEF
494: structure) is negative, then the characters will be flipped
495: around the baseline and displayed upside down. If the
496: character box width (the cx field) is negative, the
497: individual characters are flipped around the vertical axis.
498: Moreover, GpiCharStringAt will draw a character string from
499: right to left. It's as if the whole character string is
500: flipped around the vertical line at the left side of the
501: first character.
502:
503: The function in VF03.C displays the same string four times,
504: using all possible combinations of negative and positive
505: character box dimensions. You can run this function by
506: selecting "Mirrored Font" from the VECTFONT menu.
507:
508:
509: Vector Fonts and Transformations
510:
511: Unlike image fonts, vector fonts can be scaled to any size
512: and sheared and rotated to any angle. The matrix transforms
513: described in my article "OS/2 Graphics Programming
514: Interface: An Introduction to Coordinate Spaces" (Microsoft
515: Systems Journal, Volume 3, Number 4) affect vector fonts in
516: the same way they affect the display of other graphics
517: primitives.
518:
519: In addition, GPI also supports several functions
520: specifically for performing transforms on vector fonts.
521: We've already seen how the GpiSetCharBox function allows
522: font characters to be scaled. The GpiSetCharAngle rotates
523:
524:
525:
526:
527:
528:
529:
530:
531:
532:
533:
534:
535: the font characters and the GpiSetCharShear performs x-
536: shear.
537:
538:
539: Character Angle and Rotation
540:
541: By default, the baseline of the vector font characters is
542: parallel to the x axis in world coordinates. You can change
543: this by calling GpiSetCharAngle. This rotates the vector
544: fonts characters.
545:
546: The character angle is specified using a GRADIENTL
547: structure, which has two fields named x and y of type LONG.
548: Imagine a line connecting the point (0,0) to the point (x,y)
549: in world coordinates. The baseline of each character is
550: parallel to this line. The direction of the text is the same
551: as the direction from (0,0) to (x,y).
552:
553:
554:
555:
556:
557:
558:
559:
560:
561:
562:
563:
564:
565:
566:
567:
568:
569:
570:
571:
572:
573:
574:
575:
576:
577:
578:
579:
580:
581:
582:
583:
584:
585:
586:
587:
588:
589:
590:
591:
592:
593:
594:
595:
596:
597:
598:
599:
600:
601: You can also think of this in trigonometric terms. The
602: baseline of the text is parallel to a line at angle a
603: measured counterclockwise from the x-axis, where:
604:
605:
606: a = arctan (y/x)
607:
608:
609: and y and x are the two fields of the GRADIENTL structure.
610:
611:
612:
613: The absolute magnitudes of y and x are not important. What's
614: important are the relative magnitudes and signs. The signs
615: of x and y determine the direction of the text string as
616: indicated in the following table:
617:
618:
619: x y Direction
620: - - ---------
621:
622: + + To upper right
623: - + To upper left
624: - - To lower left
625: + - To lower right
626:
627:
628: The function in VF04.C uses the GpiSetCharAngle function to
629: display eight text strings at 45 degree increments around
630: the center of the client window. Each string displays the
631: fields of the GRADIENTL structure that is used in the
632: GpiSetCharAngle call.
633:
634: In this example, the text strings begin with a blank
635: character so as not to make a mess of overlapping characters
636: in the center of the client window. The character angle does
637: not affect the interpretation of the starting position of
638: the string specified in the GpiCharStringAt function. If you
639: move your head so that a particular string is seen as
640: running left to right, the starting position still refers to
641: the point at the baseline of the left side of the first
642: character.
643:
644: You can make the characters in a text string follow a curved
645: path by individually calculating the starting position an
646: angle of each character and displaying the characters one at
647: a time. This is what is done in VF05.C to display "Hello,
648: world!" around the perimeter of a circle.
649:
650: The text string is scaled based on the circumference of a
651: circle that is positioned in the center of the window and
652: has a diameter half the width or height (whichever is less)
653: of the window. The GpiQueryWidthTable function is used to
654:
655:
656:
657:
658:
659:
660:
661:
662:
663:
664:
665:
666:
667: obtain the width of individual characters and then space
668: them around the circle.
669:
670:
671: Character Shear
672:
673: It is easy to confuse the character angle and character
674: shear. Lets look at the difference. The character angle
675: refers to the orientation of the baseline. Text displayed
676: with various character angles is rotated but otherwise not
677: distorted in any way.
678:
679: The character shear affects the appearance of the characters
680: themselves apart from any rotation. Character shear by
681: itself "bends" characters to the left or right, but the
682: bottom of each character remains parallel to the x-axis. You
683: can use character shear to create oblique (sometimes
684: mistakenly called italic) versions of a font.
685:
686: To set character shear you call the GpiSetCharShear
687: function. This function requires a pointer to a structure of
688: type POINTL, which has two fields named x and y. Imagine a
689: line drawn from (0,0) to the point (x,y) in world
690: coordinates. The left and right sides of each character are
691: parallel to this line.
692:
693: The function shown in in VF06.C displays seven text strings
694: using different character shears.
695:
696: You can run this function by selecting "Character Shear"
697: from the VECTFONT menu. Each string displays the x and y
698: values used in the POINTL structure to set the character
699: shear.
700:
701: The character shear is governed by the relative magnitudes
702: and signs of the x and y fields of the POINTL structure. If
703: the signs of both fields are the same, the characters tilt
704: to the right; if different, the characters tilt to the left.
705: The character shear does not cause characters to be flipped
706: upside down. For example, character shear using the point
707: (100,100) has the same effect as (-100,-100).
708:
709: The angle of the left and right sides of the characters from
710: the y axis is sometimes called the shear angle. In theory,
711: the shear angle can range to just above -180 degrees
712: (infinite left shear) to just under +180 degrees (infinite
713: right shear) and is equal to:
714:
715:
716: a = arctan (x/y)
717:
718:
719: where x and y are the two fields of the POINTL structure.
720:
721:
722:
723:
724:
725:
726:
727:
728:
729:
730:
731:
732:
733: When you set a non-default character shear, the
734: GpiQueryTextBox function returns an array of points that
735: define a parallelogram rather than a rectangle. However, the
736: top and bottom sides of this text box are the same width as
737: for a non-sheared text string, and the distance between the
738: top and bottom sides also remains the same.
739:
740: You can use character shear to draw an oblique shadow of a
741: text string. The function in VF07.C colors the background of
742: the client window blue, and displays the text string
743: "Shadow" twice.
744:
745: The first call to GpiCharStringAt displays the shadow. This
746: is drawn in dark blue using a positive character shear. The
747: second call to GpiCharStringAt draws the characters upright
748: in red with a slightly smaller character box height. You can
749: run this function by selecting "Font with Shadow" from the
750: VECTFONT menu.
751:
752:
753: A Primer on Paths
754:
755: To explore more capabilities of vector fonts, it's necessary
756: to become familiar with the GPI "path," which is similar to
757: a PostScript path. In GPI, you create a path by calling line
758: drawing functions between calls to the GpiBeginPath and
759: GpiEndPath functions:
760:
761:
762: GpiBeginPath(hps, idPath);
763: <... call line
764: drawing
765: functions ... >
766: GpiEndPath (hps) ;
767:
768:
769: This is called a "path bracket." In OS/2 1.1, idPath must be
770: set equal to 1L. The functions that are valid within a path
771: bracket are listed in the documentation of the Presentation
772: Manager functions.
773:
774: The functions you call within the path bracket do not draw
775: anything. Instead, the lines that make up the path are
776: retained by the system. Often the lines you draw in a path
777: will enclose areas, but they don't have to.
778:
779: After the GpiEndPath call, you can do one of three things
780: with the path you've created:
781:
782: * Call GpiStrokePath to draw the lines that comprise
783: the path. These lines are drawn using the
784: geometric line width, joins, and ends (discussed
785: shortly).
786:
787:
788:
789:
790:
791:
792:
793:
794:
795:
796:
797:
798:
799: * Call GpiFillPath to fill enclosed areas defined by
800: the path. Any open areas are automatically
801: closed. The area is filled with the current
802: pattern.
803:
804: * Call GpiSetClipPath to make the enclosed areas of
805: the path a clipping area. Any open areas are
806: automatically closed. Subsequent GPI calls will
807: only display output within the enclosed area
808: defined by the path.
809:
810: Each of these three functions cause the path to be deleted.
811: Prior to calling any of these three functions you can call
812: GpiModifyPath, which I'll describe towards the end of this
813: article.
814:
815: Normally, GpiCharStringAt and the other text output
816: functions are not valid in a path bracket. The exception is
817: when a vector font is selected in the presentation space.
818: When called from within a path bracket, GpiCharStringAt does
819: not draw the text string. Instead, the outlines of the
820: characters become part of the path.
821:
822: This facility opens up a whole collection of PostScript-like
823: stylistic techniques that you can use with vector fonts.
824:
825:
826: Hollow Characters
827:
828: Let's begin by calling GpiCharStringAt in a path bracket and
829: then use GpiStrokePath to draw the lines of the path.
830: GpiStrokePath has the following syntax:
831:
832:
833: GpiStrokePath(
834: hps, idPath, 0L);
835:
836:
837: In the initial version of the Presentation Manager, the last
838: parameter of the function must be set to 0L. When used to
839: stroke a path created by calling GpiCharStringAt, only the
840: outline is drawn and not the interiors. This creates hollow
841: characters.
842:
843: The function in VF08.C uses this technique to display the
844: outline of the characters in the text string "Hollow." You
845: can run this function by selecting "Hollow Font" from the
846: VECTFONT menu.
847:
848: You may want to display characters in one color with an
849: outline of another color. In this case, you must call
850: GpiCharStringAt twice, first to draw the interior in a
851: specific color, and secondly in a path bracket followed by a
852: GpiStrokeFont call to draw the outline.
853:
854:
855:
856:
857:
858:
859:
860:
861:
862:
863:
864:
865:
866: The function in VF09.C does something like this to draw text
867: with a drop shadow.
868:
869: The shadow is drawn first using a normal GpiCharStringAt
870: call. Another GpiCharStringAt functions draws the text again
871: in the current window background color at a 1/6 inch offset
872: to the first string. This is surrounded by an outline
873: created by a third GpiCharStringAt call in a path bracket
874: followed by GpiStrokeFont.
875:
876: Quite similar to this is the creation of characters that
877: look like solid blocks, as shown in the function in VF10.C.
878: Eighteen character strings are drawn at 1 point offsets
879: using CLR_DARKGREEN. This is capped by the character string
880: drawn again in CLR_GREEN and the border in CLR_DARKGREEN.
881:
882:
883:
884:
885:
886:
887:
888:
889:
890:
891:
892:
893:
894:
895:
896:
897:
898:
899:
900:
901:
902:
903:
904:
905:
906:
907:
908:
909:
910:
911:
912:
913:
914:
915:
916:
917:
918:
919:
920:
921:
922:
923:
924:
925:
926:
927:
928:
929:
930:
931: Geometrically Thick Lines
932:
933: At first, it may seem as if there is no difference between
934: drawing a line normally, like this:
935:
936:
937: GpiMove(hps, &ptlBeg);
938: GpiLine(hps, &ptlEnd);
939:
940:
941: and calling these same two functions within a path bracket
942: and then stroking the path, like this:
943:
944:
945: GpiBeginPath(hps, idPath);
946: GpiMove(hps, &ptlBeg);
947: GpiLine(hps, &ptlEnd);
948: GpiEndPath(hps)
949: GpiStrokePath(hps, idPath, 0);
950:
951:
952: There are, in fact, some very significant differences.
953:
954: First, the line drawn with the normal GpiLine function has
955: what is called a "cosmetic" line width. The default width of
956: the line is based on the resolution of the output device. It
957: is a device dependent width for a "normal" line. The width
958: of the line does not change when you use matrix transforms
959: to set different scaling factors in the coordinate space.
960: Although GPI provides a function called GpiSetLineWidth to
961: change the cosmetic line width, this function is not
962: implemented in OS/2 1.1.
963:
964: But a line drawn by stroking a path has a "geometric" line
965: width. This is a line width (in world coordinates) that you
966: set with the GpiSetLineWidthGeom function. Because this line
967: width is specified in world coordinates, it is affected by
968: any scaling that you set using matrix transforms.
969:
970: Secondly, a line draw with GpiLine can have different line
971: types that you set with the GpiSetLineType function. These
972: line types are various combinations of dots and dashes. The
973: line is drawn with the current line color and the current
974: line mix.
975:
976: But a line drawn by stroking a path does not use the line
977: type. The line is instead treated as an area that follows
978: the path of the line but which has a geometric width. This
979: area is filled with the pattern that you set with
980: GpiSetPattern, colored with the current pattern foreground
981: and background color, and the current pattern foreground and
982: background mix.
983:
984:
985:
986:
987:
988:
989:
990:
991:
992:
993:
994:
995:
996:
997: Third, a line drawn by stroking the path can have various
998: types of line "joins" and "ends." By calling GpiSetLineJoin
999: you can specify that lines meet with a rounded, square, or
1000: miter join. GpiSetLineEnd lets you specify rounded, square,
1001: or flat ends to the lines.
1002:
1003: The function in the VF11.C file demonstrates the use of
1004: geometrically thick lines filled with patterns to give the
1005: letters a kind of "neon" look.
1006:
1007: You can run this function by selecting "Neon Effect" from
1008: the VECTFONT menu. The function strokes the path using
1009: various geometric line widths filled with a PATSYM_HALFTONE
1010: pattern and several colors. The outline of the font is
1011: white, but surrounded with a halo of red.
1012:
1013: A better effect could be achieved on devices capable of more
1014: than 16 colors. In this case, you can use a solid pattern
1015: but color each stroke with a different shade of red.
1016:
1017:
1018: Filling the Path
1019:
1020: When introducing paths earlier in this article, I mentioned
1021: that you can do one of three things with a path: stroke it,
1022: fill it, or use it for clipping. Let's move on to the
1023: second: filling the path.
1024:
1025: To fill a path, you call:
1026:
1027:
1028: GpiFillPath(hps,
1029: idPath, lOption);
1030:
1031:
1032: This fills the path with the current pattern. Any open areas
1033: of the path are automatically closed before being filled.
1034: The lOption parameter can be either FPATH_ALTERNATE or
1035: FPATH_WINDING to fill the path using alternate or winding
1036: modes. For vector fonts, FPATH_WINDING causes the interiors
1037: of some letters (such as "O") to be filled. You'll probably
1038: want to use FPATH_ALTERNATE instead.
1039:
1040: If the current area filling pattern is PATSYM_SOLID, then
1041: the code:
1042:
1043:
1044: GpiBeginPath(hps, idPath);
1045: GpiCharStringAt(hps, &ptl,
1046: cch, szText);
1047: GpiEndPath(hps);
1048: GpiFillPath(hps,
1049: idPath,
1050: FPATH_ALTERNATE);
1051:
1052:
1053:
1054:
1055:
1056:
1057:
1058:
1059:
1060:
1061:
1062:
1063:
1064:
1065: does roughly the same thing with a vector font as a
1066: GpiCharStringAt by itself. When using GpiFillPath you'll
1067: want to set a pattern other than PATSYM_SOLID. (A bug in
1068: OS/2 1.1 causes the current pattern to be reset to
1069: PATSYM_SOLID during a path bracket in which GpiCharStringAt
1070: is called. You can get around this bug by calling
1071: GpiSetPattern after you end the path.)
1072:
1073: The function in VF12.C uses GpiFillPath to display the text
1074: string "Fade" eight times filled with the eight GPI shading
1075: patterns (PATSYM_DENSE1 through PATSYM_DENSE8) and then
1076: finishes by calling GpiCharStringAt outside of a path
1077: bracket. You can run this function by selecting "Fading
1078: Font" from the VECTFONT menu.
1079:
1080:
1081: Clipping to the Text Characters
1082:
1083: The third option after creating a path is to call
1084: GpiSetClipPath:
1085:
1086:
1087: GpiSetClipPath(hps, idPath,
1088: lOption);
1089:
1090: The lOption parameter can be either SCP_RESET (which equals
1091: 0L, so it's the default) or SCP_AND. The SCP_RESET option
1092: causes the clipping path to be reset so that no clipping
1093: occurs. The SCP_AND option sets the new clipping path to the
1094: intersection of the old clipping path and the path you've
1095: just defined in a path bracket. Any open areas in the path
1096: are automatically closed.
1097:
1098: You can combine the SCP_AND option with either SCP_ALTERNATE
1099: (the default) or SCP_WINDING. As with GpiFillPath, you'll
1100: probably want to use alternate mode when working with paths
1101: created from vector fonts
1102:
1103: The function in VF13.C calls GpiCharStringAt with the text
1104: string "WOW" within a path bracket. This is followed by a
1105: call to GpiSetClipPath. The clipping path is now the
1106: interior of the letters. The function draws a series of
1107: colored lines emanating from the center of the client
1108: window.
1109:
1110: The function in VF14.C uses a similar technique but draws a
1111: series of areas defined by splines.
1112:
1113:
1114: Modifying the Path
1115:
1116:
1117:
1118:
1119:
1120:
1121:
1122:
1123:
1124:
1125:
1126:
1127:
1128:
1129: Between the call to GpiEndPath to end the path and the call
1130: to GpiStrokePath, GpiFillPath, or GpiSetClipPath, you can
1131: call GpiModifyPath. This function uses the current geometric
1132: line width, line join, and line end to convert every line in
1133: the path to a new line that encloses an area around the old
1134: line.
1135:
1136: For example, suppose that the path contained a single
1137: straight line. After GpiModifyPath the path would contain a
1138: closed line in the shape of a hotdog. The width of this
1139: hotdog is the geometric line width. The ends of the hotdog
1140: could be round, square, or flat, depending on the current
1141: line end attribute.
1142:
1143:
1144:
1145:
1146:
1147:
1148:
1149:
1150:
1151:
1152:
1153:
1154:
1155:
1156:
1157:
1158:
1159:
1160:
1161:
1162:
1163:
1164:
1165:
1166:
1167:
1168:
1169:
1170:
1171:
1172:
1173:
1174:
1175:
1176:
1177:
1178:
1179:
1180:
1181:
1182:
1183:
1184:
1185:
1186:
1187:
1188:
1189:
1190:
1191:
1192:
1193:
1194:
1195: Following the creation of a path, these two functions in
1196: succession:
1197:
1198:
1199: GpiModifyPath(hps, ID_PATH,
1200: MPATH_STROKE);
1201: GpiFillPath(hps, ID_PATH,
1202: FPATH_WINDING) ;
1203:
1204:
1205: is usually equivalent to:
1206:
1207:
1208: GpiStrokePath(hps, ID_PATH,
1209: 0L);
1210:
1211:
1212: GpiModifyPath and GpiStrokePath are the only two functions
1213: that use the geometric line width, joins, and ends.
1214:
1215: In theory, you can call GpiStrokePath after GpiModifyPath,
1216: like this:
1217:
1218:
1219: GpiModifyPath(hps, ID_PATH,
1220: MPATH_STROKE);
1221: GpiStrokePath(hps, ID_PATH,
1222: 0L);
1223:
1224:
1225: This should do something, and it should be rather
1226: interesting, but GPI usually reports that it can't create
1227: the path because it's too complex.
1228:
1229: Instead, let's look at GpiModifyPath followed by
1230: GpiSetClipPath. The function in VF15.C is almost the same as
1231: the one in VF13.C except that it sets the geometric line
1232: width to 6 (1/12 inch) and calls GpiModifyPath before
1233: calling GpiSetClipPath.
1234:
1235: Note that the colored lines are clipped not to the interior
1236: of the characters, but to their original outlines. By the
1237: use of GpiModifyPath, the outlines of the characters have
1238: themselves been made into a path that is 1/12 inch wide.
1239: This is the path that is used for clipping.
1240:
1241:
1242: Is It Enough?
1243:
1244: I think it's clear that the facilities provided by GPI for
1245: working with vector fonts equal -- and sometimes exceed --
1246: those in PostScript. The GPI interface is very powerful and
1247: very versatile.
1248:
1249:
1250:
1251:
1252:
1253:
1254:
1255:
1256:
1257:
1258:
1259:
1260:
1261: Is that enough?
1262:
1263: No, it's not. The implementation of vector fonts in GPI has
1264: a structural flaw that still leaves PostScript the king.
1265:
1266: Take a close look at the display of the "Helv" font. You'll
1267: notice that the two legs of the "H" are different in width
1268: by one pixel when they should be the same width. This is
1269: undoubtedly due to a rounding error. It's obviously more
1270: noticeable on a low-resolution video display than it would
1271: be on a 300 dpi laser printer, but even on a laser printer
1272: such errors will affect the legibility of the text.
1273:
1274: Errors such as this do not occur with PostScript fonts.
1275: PostScript fonts are true algorithms that are able to
1276: recognize and correct any anomalies in the rendition of the
1277: characters. In contrast, GPI fonts (which are encoded as a
1278: simple series of polylines and polyfillets) are drawn
1279: blindly without any feedback or correction.
1280:
1281: So, while we can rejoice in what we have in GPI, there is
1282: still the need to hope for improvement.
1283:
1284:
1285:
1286:
1287:
1288:
1289:
1290:
1291:
1292:
1293:
1294:
1295:
1296:
1297:
1298:
1299:
1300:
1301:
1302:
1303:
1304:
1305:
1306:
1307:
1308:
1309:
1310:
1311:
1312:
1313:
1314:
1315:
1316:
1317:
1318:
1319:
1320:
1321:
1322:
1323:
1324:
1325:
1326:
1327: Figure 1
1328:
1329:
1330: Dynamic Link
1331: Library File Image Fonts Vector Fonts
1332: ------------ ----------- ------------
1333:
1334: COURIER.FON "Courier" (8, 10, and "Courier"
1335: 12 points for CGA, "Courier Bold"
1336: EGA, VGA, and "Courier Italic"
1337: IBM Proprinter) "Courier Bold Italic"
1338:
1339: HELV.FON "Helv" (8, 10, 12, 14, "Helv"
1340: 18, and 24 points "Helv Bold"
1341: for CGA, EGA, VGA, "Helv Italic"
1342: and IBM Proprinter) "Helv Bold Italic"
1343:
1344: TIMES.FON "Tms Rmn" (8, 10, 12, "Tms Rmn"
1345: 14, 18, and 24 points "Tms Rmn Bold"
1346: for CGA, EGA, VGA, "Tms Rmn Italic"
1347: and IBM Proprinter) "Tms Rmn Bold Italic"
1348:
1349:
1350: Caption: The OS/2 1.1 dynamic link library files that
1351: Caption:
1352: contain fonts. The font face names are shown in quotation
1353: marks.
1354:
1355:
1356:
1357:
1358:
1359:
1360:
1361:
1362:
1363:
1364:
1365:
1366:
1367:
1368:
1369:
1370:
1371:
1372:
1373:
1374:
1375:
1376:
1377:
1378:
1379:
1380:
1381:
1382:
1383:
1384:
1385:
1386:
1387:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.