Wlodzimierz Bzyl
matwb@univ.gda.pl
Abstract
Fonts are collections of symbols which allow people to express what they want
to say, what they think or feel. Writing is a technique and as each technique
has something to offer and has limitations. For example, the shapes of symbols
depend on the tools and materials used for writing.
In the first part, I illustrate some writing techniques with examples. In
the second part, I present a new technique for creating fonts and illustrate it
with several examples. It is based on the METAPOST language [1] and could be
viewed as Knuth’s method [2–5] adapted to METAPOST. Knuth uses METAFONT
to program fonts and an mf compiler to translate programs into bitmap fonts.
Unfortunately, today’s standards are based on PostScript fonts [6–9]. So, to keep
the Knuth’s idea of programmable shapes alive, fonts should be programmed in
PostScript. This is difficult, because PostScript is a low level language.
The approach presented here is to program fonts in METAPOST. Although
the mpost compiler is not able to output a font directly, its output can be
assembled into a PostScript font [10–13]. A font programming environment
is based on a revised version of the mft pretty-printer. The original mft
understands only METAFONT, but changed mft understands METAPOST too.
In the third part, I present a simple font programmed as a Type 3 and as a
Type 1 font. These examples will give an idea of font programming.
In the Appendix, I present a detailed description of Type 3 fonts [6, 9].
Typographical journey
Exploring type [with computer] is fun,
and ultimately, it changes the way you
think about type and work with it.
— ROB CARTER, Experimental Typography
STOP !
STOP !
STOP !
STOP !
Fig. 11
3
Listen sons of Kahless!
Listen his daughters!
4
LI
To Shine Brightly, to Part
INTERPRETATION
To Part. It is useful to stand firm and behave well. This will bring
success. Take care of the cows. There will be good fortune.
various font data to several files. These data are numeric px; px:=100;
used by the mkfont1 script which assembles Type 1 numeric py; py:=90;
font and mkproof1 script which typesets hardcopy default_nib:=fix_nib(px,py,0);
proofs. These names are intended to make the code more
The Type 1 font programmed below contains noth- readable.
ing but a plus symbol. Let’s start with reading path vertical_stem, horizontal_stem;
basic macros. path glyph;
input type1; Each glyph should be defined within a block defined
Next follows the usual font administration stuff. by beginfont and endfont commands.
Each font should define several variables [9, Tables beginfont
5.1–4]. Programmed symbols must be given names as well
pf_info_familyname "Plus"; as positions in the font.
pf_info_fontname "Plus-Regular"; encode("plus",43);
pf_info_weight "Normal";
Each glyph starts with beginglyph and ends with
pf_info_version "1.0";
pf_info_fixedpitch true; endglyph macro. The following macros initialize
several variables, used for the glyph data bookkeep-
pf_info_author "Anonymous 2002";
pf_info_creationdate; ing.
The mpost program does all its drawing on its standard_introduce("plus");
internal ‘graph paper’ with 1000 × 1000 coordinate beginglyph("plus");
space on it. The data below provides information For convenience, the width, height and depth of the
about how to typeset with this font. character are assigned to variables w, h, and d.
pf_info_quad 760; w:=760; h:=760; d:=0;
pf_info_capheight 760; The horizontal and vertical bars of the plus glyph
pf_info_xheight 760; are centered with respect its bounding box.
pf_info_space 333; z0=(w/2,d); z1=(w/2,h);
The adl suffix here is a mnemonic for Ascender, z2=(0,(h-d)/2); z3=(w,(h-d)/2);
Descender, and Lineskip.
To draw paths z0--z1 and z2--z3 the pen with
pf_info_adl 750, 250, 0; a default_nib-shaped nib is used. The macro
The PostScript fill operator is used to paint the pen_stroke finds the outline of each path. Out-
entire region closed by the current path. For each lines are assigned to the paths vertical_stem and
path, the non-zero winding number rule [9, p. 161] horizontal_stem. The macro butt_end cuts off
determines whether a given point is inside a path. the ends of these paths at times 0 (beginning) and
This behaviour is simulated by the Fill and unFill 1 (end).
macros. The fill_outline macro, for each closed pen_stroke(butt_end(0,1))(z0--z1)
path stored in the array s[1..s.num], fills or unfills (vertical_stem);
it based on its turning number [4, p. 111]. pen_stroke(butt_end(0,1))(z2--z3)
def fill_outline suffix s = (horizontal_stem);
for i:=1 upto s.num: Programming a Type 1 glyph means constructing
if turningnumber s[i] > 0: Fill its outline (which could be made up of several cyclic
else: unFill fi s[i]; paths). The macro below finds the outline of the
endfor paths constructed above and stores it in the array
enddef; named in the second argument.
The plus sign has squared-off ends. Macro butt_end find_outlines
simplifies the task of cutting of ends of paths. (vertical_stem,horizontal_stem)(glyph);
def butt_end(text nodes) = Now, we are ready to draw the plus symbol.
cut(rel 90)(nodes)
fill_outline glyph;
enddef;
Finally, we fix the width of the glyph to w and its
A horizontal line of the same width as a vertical
left and right sidebearings to 0.
line seems thicker. To avoid this optical illusion we
use an elliptical pen. fix_hsbw(w,0,0);
/FontType 3 def
/LanguageLevel 2 def
/FontMatrix [ 0.001 0 0 0.001 0 0 ] def
0
/FontBBox [ 0 0 1000 1000] def
The FontInfo dictionary is optional. All infor-
mation stored there is entirely for the benefit of
PostScript language programs using the font, or for
encode("plus", 43) ;
standard introduce("plus") ; documentation.
beginglyph("plus") ;
w := 760 ; h := 760 ; d := 0 ; FamilyName — a human readable name for a
z0 = (w/2, d) ; z1 = (w/2, h) ;
z2 = (0, (h − d)/2) ; z3 = (w, (h − d)/2) ; group of fonts. All fonts that are members
pen stroke(butt end (0, 1))(z0 - - z1 )(vertical stem) ;
pen stroke(butt end (0, 1))(z2 - - z3 )(horizontal stem) ;
find outlines(vertical stem, horizontal stem)(glyph) ;
of such a group should have exactly the same
fill outline glyph ; FamilyName.
fix hsbw(w, 0, 0) ;
fix hstem(py )(horizontal stem) ;
FullName — unique, human readable name for
fix vstem(px )(vertical stem) ;
dotlabels(0, 1, 2, 3) ;
an individual font. Should be the same name
endglyph ; as one used when registering the font with the
endfont ;
definefont operator below.
21:05 17 X 2002 PLUS 3 Notice — copyright, if applicable.
Weight — name for the “boldness” attribute of should be used, which is similar to setcachede-
a font. vice, but declares that the character being defined
version — version number of the font program. is not to be placed in the font cache.
ItalicAngle — angle in degrees counterclock-
wx wy lx ly ux uy setcachedevice –
wise from the vertical of the dominant vertical
wx , wy — comprise the basic width vector, i.e.,
strokes of the font.
the normal position of the origin of the next
isFixedPitch — if true, indicates that the font
character relative to origin of this one
is a monospaced font; otherwise set false.
lx , ly , ux , uy — are the coordinates of this
UnderlinePosition — recommended distance
character bounding box
from the baseline for positioning underlining
wx wy setcharwidth –
strokes (y coordinate).
wx wy — comprise the basic width vector of
UnderlineThickness — recommended stroke
this character
width for underlining, in units of the char-
acter coordinate system. CharacterProcedures /.notdef {
1000 0 0 0 1000 1000 setcachedevice
/FontInfo << 1000 0 moveto
/FamilyName (Geometric) } put
/FullName (Square) Encoding 32 /space put
/Notice (Type 3 Repository. CharacterProcedures /space {
Copyright \(C\) 2001 Anonymous. 1000 0 0 0 1000 1000 setcachedevice
All Rights Reserved.) 1000 0 moveto
/Weight (Medium) } put
/version (1.0) Encoding 83 /square put % ASCII ‘S’
/ItalicAngle 0 CharacterProcedures /square {
/isFixedPitch true 1000 0 setcharwidth
/UnderlinePosition 0.0 0 1 1 0 setcmykcolor % red
/UnderlineThickness 1.0 0 0 1000 1000 rectfill
>> def } put
The Encoding array maps character codes (integers) The BuildGlyph procedure is called within the
to character names. All unused positions in the confines of a gsave and a grestore, so any changes
encoding vector must be filled with the name BuildGlyph makes to the graphics state do not
.notdef. It is special in only one regard: if some persist after it finishes.
encoding maps to a character name that does not BuildGlyph should describe the character in
exist in the font, .notdef is substituted. The effect terms of absolute coordinates in the character
produced by executing .notdef character is at the coordinate system, placing the character origin at
discretion of the font designer, but most often it is (0, 0) in this space.
the same as space. The Current Transformation Matrix (CTM)
/Encoding 256 array def and the graphics state are inherited from the envi-
0 1 255 ronment. To ensure predictable results despite font
{Encoding exch /.notdef put} caching, BuildGlyph must initialize any graphics
for state parameter on which it depends. In particular,
The CharacterProcedures dictionary contains in- if BuildGlyph executes the stroke operator, it
dividual character definitions. The name is not should explicitly set: dash parameters, line cap, line
special — any name could be used — but this name join, line width. These initializations are unneces-
is assumed by the BuildGlyph procedure below. sary if characters are not cached, for example if the
setcachedevice operator is not used.
/CharacterProcedures 256 dict def
When a PostScript language interpreter tries
Each character must invoke one of the setcachede- to show a character from a font, and the character
vice and setcharwidth operators before executing is not already present in the font cache it pushes
graphics operators to define and paint the char- current font dictionary and character name onto
acter. The setcachedevice operator stores the the operand stack. The BuildGlyph procedure
bitmapped image of the character in the font cache. must remove these two objects from the operand
However, caching will not work if color or gray is
used. In such cases the setcharwidth operator
stack and use this information to render the re- [4] Donald E. Knuth. 1986. The METAFONTbook.
quested character. This typically involves finding American Mathematical Society and Addison
the character procedure and executing it. Wesley.
/BuildGlyph { % stack: font charname [5] Donald E. Knuth. 1992. Computer Modern
exch Typefaces. Addison Wesley.
begin [6] Adobe Systems Incorporated. 1985. Tutorial and
% initialize graphics state parameters Cookbook. Addison Wesley.
% turn dashing off: solid lines [7] Adobe Systems Incorporated. 1992. The Post-
[ ] 0 setdash Script Font Handbook. Addison Wesley.
% projecting square cap [8] Adobe Systems Incorporated. 1993 (3rd print-
2 setlinecap ing), Version 1.1. Adobe Type 1 Font Format.
% miter join Addison Wesley.
0 setlinejoin [9] Adobe Systems Incorporated. 1999 (3rd print-
% thickness of lines rendered by ing). PostScript Language Reference Manual. Ad-
% execution of the stroke operator dison Wesley.
50 setlinewidth [10] Boguslaw Jackowski et al. 1999. “Antykwa
% the miter limit controls the stroke Póltawskiego: a parameterized outline font.” Eu-
% operator’s treatment of corners; roTEX 99 Proceedings. Ruprecht-Karls-Univerität
% this is the default value and it Heidelberg, 117–141.
% causes cuts off mitters at [11] Boguslaw Jackowski, Janusz M. Nowacki, and
% angles less than 11 degrees Piotr Strzelczyk. 2001. “METATYPE1: A Meta-
10 setmiterlimit Post-based engine for generating Type 1 fonts.”
CharacterProcedures exch get exec EuroTEX 2001 Proceedings. Kerkrade, the Nether-
end lands, 111–119.
} bind def [12] Wlodzimierz Bzyl. 2001. “Re-introducing Type 3
currentdict fonts to the world of TEX.” EuroTEX 2001 Pro-
end % of font dictionary ceedings. Kerkrade, the Netherlands, 219–243.
[13] Apostolos Syropoulos. 2000. “The MF2PT3
Finally, we register the font name as a font dic-
tool.” Available online from
tionary defined above and associate it with the
www.obelix.ee.duth.gr/~apostolo.
key Square. Additionally the definefont operator
[14] Rob Carter. 1997. Experimental Typography.
checks if the font dictionary is a well-formed.
A RotoVision Book. Watson Guptill Publications.
/Square exch definefont pop [15] František Muzika. 1965. Die Schöne Schrift.
If the following lines are not commented out the Verlag Werner Dausien, Hanau/Main. Vol I & II.
Ghostscript program (a public domain PostScript [16] Halina Thórzewska Ed. 2000. More Precious
interpreter) will show the text below online. Obvi- Than Gold. Treasures of the Polish National Li-
ously, these lines should be commented out in the brary. Biblioteka Narodowa. Warszawa.
final version of the font program. [17] Charlotte & Peter Fiell. 1999. William Morris
/Square findfont (1834–1896). Benedikt Taschen Verlag GmbH.
72 scalefont setfont [18] J.R.R. Tolkien. 1981. The Fellowship of the
0 72 moveto (S) show Ring. Sp´ldzielnia Wydawnicza “Czytelnik”.
showpage Warszawa.
[19] Donald E. Knuth. 1988. “A Punk Meta-Font”.
TUGboat 9, 152–168.
References [20] Richard M. Stallman and Roland McGrath.
[1] John D. Hobby. 1992. A User’s Manual for Meta- GNU Make. Available online as a part of GNU
Post. Technical Report 162. AT&T Bell Labora- MAKE package.
tories, Murray Hill / New Jersey. Available online [21] Per Cederqvist et al. Version Management with
as a part of METAPOST distribution. CVS. Available online with the CVS package.
[2] Donald E. Knuth. 1982. “The Concept of a Signum Support AB.
Meta-Font.” Visible Language 16, 3–27. [22] Mark Shoulson, 1994. Okuda Font. METAFONT
[3] Donald E. Knuth. 1985. “Lessons Learned from source available online from CTAN/fonts/okuda.
METAFONT.” Visible Language 19, 35–53. [23] Karol Jarmakiewicz. 2002. Czcionka Klingońska.
Instytut Matematyki, Uniwersytet Gdański.
[24] Mieszko Zieliński. 2002. Kto i dlaczego wymyślil [29] Alan M. Stanier. 1994. METAFONT source
Tengwar. Instytut Matematyki, Uniwersytet Gda- available online from CTAN/fonts/iching.
ński. [30] Leslaw Furmaga. 1999. Ortofrajda. Pamieciowo-
[26] Wojciech Górski. 2002. Font Fenicki. Instytut wzrokowy slownik ortograficzny dla dzieci. INTE-
Matematyki, Uniwersytet Gdański. GRAF, Sopot.
[27] Slawomir Lis. 2002. Pismo Rȩczne. Instytut [31] Jan Jelinek. 1977. Wielki Atlas Prahistorii
Matematyki, Uniwersytet Gdański. Czlowieka. Państwowe Wydawnictwo Rolnicze
[28] Jacek Neuman. 2002. Just Smiley!. Instytut i Leśne. Warszawa.
Matematyki, Uniwersytet Gdański.