<< . .

. 40
( : 45)



. . >>

GFtoDVI, as we know from the experiments in Chapter 5. It™s also possible to study
low-resolution characters with GFtoDVI, especially if plain ™s ˜gfcorners™
feature has been used. We shall now take a thorough look at what GFtoDVI can do.
All communication from to GFtoDVI comes through the gf ¬le
and from options that you might type when you run GFtoDVI. If there are no “special”
commands in the gf ¬le (cf. Appendix G), each page of GFtoDVI™s output will show just
the “black” pixels of a character; furthermore there will be a title line at the top of the
page, showing the date and time of the run, together with the character
code number and extension code (if they are nonzero). The black pixels are typeset via
characters of a so-called “gray font,” described in detail below; by changing the gray
font you can produce a variety of di¬erent outputs from a single gf ¬le.
To get other things on your proof sheets, “special” commands must appear in
the gf ¬le. For example, will automatically output a title command, if
proo¬ng > 0, as explained in Appendix G; GFtoDVI will typeset this title on the title
line of the next character image that follows the command. If there are several title
statements, they all will appear; they are supposed to ¬t on a single line.
The most important special commands tell GFtoDVI to create labeled points
on the character diagram. When you say, for example, ˜labels(1, 2)™ in a plain -
program, at a time when proo¬ng > 1, the macros of Appendix B will convert
this to the special commands
special " 01"; numspecial x1 ; numspecial y1 ;
special " 02"; numspecial x2 ; numspecial y2 ;
GFtoDVI will then put a dot labeled ˜1™ at point (x1 , y1 ) and a dot labeled ˜2™ at (x2 , y2 ).
Labels are placed in one of four positions relative to their dots”either at the
top, the left, the right, or the bottom. GFtoDVI will ordinarily try to place all labels
so that they don™t interfere with each other, and so that they stay clear of other dots.
But if you want to exercise ¬ne control over the placement yourself, you can say, for
example, ˜labels.top (1a, 2a)™; in this case the speci¬ed labels will appear above their
dots, regardless of whether or not other labels and/or dots are thereby overprinted.
328 Appendix H: Hardcopy Proofs


The gf ¬le in this case will contain labels.top
makelabel
nodot
special " 11a"; numspecial x1a ; numspecial y1a ;
nodot
special " 12a"; numspecial x2a ; numspecial y2a . over¬‚ow equation
/
GFtoDVI looks at the character following a leading blank space to determine what sort lcode
of labeling convention is desired; the subsequent characters are the text of the label. rule
proofrule
The command ˜labels.top (1a, 2a)™ in plain is just an abbreviation dvi
for ˜makelabel.top ("1a", z1a ); makelabel.top ("2a", z2a )™, when proo¬ng > 1; the
makelabel macro is really the fundamental one, and you should use it directly if you
want more unusual e¬ects. Suppose, for example, you just want to put a dot but no
label at point z5 ; then you can say ˜makelabel("", z5 )™. And suppose you want to put a
label to the left of point z5 but with no dot; you can say ˜makelabel.lft .nodot ("5", z5 )™.
Furthermore you could say ˜makelabel.lft .nodot ("5", z5 ’ (2, 3))™ to move that label
left by 2 pixels and down by 3 pixels, thereby getting the e¬ect of a label that is
diagonally adjacent to its dot. Labels without dots can also be used to put words on a
diagram.
GFtoDVI recognizes nine varieties of labels in all, based on the ¬rst two char-
acters of the special string command:
makelabel (special " 0"): choose the label position automatically.
makelabel.top (special " 1"): center the label just above the dot.
makelabel.lft (special " 2"): place the label just left of the dot.
makelabel.rt (special " 3"): place the label just right of the dot.
makelabel.bot (special " 4"): center the label just below the dot.
makelabel.top .nodot (special " 5"): like top , but omit the dot.
makelabel.lft .nodot (special " 6"): like lft , but omit the dot.
makelabel.rt .nodot (special " 7"): like rt , but omit the dot.
makelabel.bot .nodot (special " 8"): like bot , but omit the dot.
The ¬rst case is called autolabeling; this is the normal command. Autolabeling always
places a dot, whether or not that dot overlaps other dots, but you don™t always get a
label. Autolabels are typeset only after all explicit labels have been established; then
GFtoDVI tries to place as many of the remaining labels as possible.
If there™s no place to put an autolabel, an “over¬‚ow equation” is put in the
upper right corner of the proofsheet. For example, the over¬‚ow equation ˜5 = 5r +
(-4.9,0)™ means that there was no room for label 5, whose dot is 4.9 pixels to the left
of the dot for 5r (which is labeled).
You can avoid over¬‚ow equations by sending GFtoDVI the special command
" /" instead of " 0"; this is a variant of autolabeling that does everything as usual
except that the label will simply be forgotten if it can™t be placed. To do this with
, set ˜lcode := " /"™ near the beginning of your program; lcode is
plain
the string that makelabel uses to specify autolabeling.
The next most important kind of annotation for proofs is a straight line or
“rule.” Plain ™s command for this is ˜proofrule(z1 , z2 )™, which expands to
special "rule"; numspecial x1 ; numspecial y1 ;
numspecial x2 ; numspecial y2 .
GFtoDVI has trouble drawing diagonal rules, because standard dvi format includes no
provision for drawing straight lines unless they are vertical or horizontal. Therefore
Appendix H: Hardcopy Proofs 329


you might get an error message unless x1 = x2 (vertical rule) or y1 = y2 (horizontal slant font
proofrulethickness
rule). However, a limited escape from this restriction is available via a “slant font,” by
proofo¬set
which GFtoDVI is able to typeset diagonal lines as sequences of characters. Only one titlefont
slope is permitted per job, but this is better than nothing (see below). labelfont
grayfont
To control the weight of proof rules, you say, e.g., ˜proofrulethickness slantfont
1.5mm #™ in a plain program; this expands to grayfontarea
labelfontat
special "rulethickness"; numspecial 1.5mm #. design size
shipout
Each horizontal or vertical rule is drawn as if by a pen of the current rulethickness, hence endchar
mode setup
you can get di¬erent weights of lines in a single diagram. If the current rulethickness is /
negative, no rule will appear; if it is zero, a default rulethickness based on a parameter
of the gray font will be used; if it is positive, the stated thickness will be increased if
necessary until it equals an integer number of pixels, and that value will be used to
draw the rule. At the beginning of each character the current rulethickness is zero.
You can reposition an entire diagram on its page by saying ˜proofo¬set (x, y)™;
this expands to
special "offset"; numspecial x; numspecial y
and it tells GFtoDVI to shift everything except the title line on the next character image,
x pixels to the right and y pixels upward.
GFtoDVI uses four fonts to typeset its output: (1) The title font is used for
the top line on each page. (2) The label font is used for all labels. (3) The gray
font is used for dots and for black pixels. (4) The slant font is used for diagonal rules.
Appropriate default fonts will be used at each installation unless you substitute speci¬c
fonts yourself, by using the special commands titlefont, labelfont, grayfont, or
slantfont. GFtoDVI also understands special strings like ˜"grayfontarea /usr/dek"™,
which can be used to specify a nonstandard ¬le area or directory name for the gray
font. Furthermore the gf ¬le might say, e.g.,
special "labelfontat"; numspecial 20
if you want the label font to be loaded at 20 pt instead of its design size. The area name
and the at size must be given after the font name itself; in other words, ˜"grayfont"™
cancels a previous ˜"grayfontarea"™.
The four fonts used by GFtoDVI must be established before the ¬rst character
bitmap appears in the gf ¬le. This means that the special font commands must be given
before the ¬rst shipout or endchar in your program; but they shouldn™t appear until
after mode setup, so that your gf ¬le will have the correct name. If it™s inconvenient
to specify the fonts that way, you can change them at run time when you use GFtoDVI:
Just type ˜/™ following the name of the gf ¬le that™s being input, and you will be asked
to type special strings online. For example, the run-time dialog might look like this:
This is GFtoDVI, Version 2.0
GF file name: io.2602gf/
Special font substitution: labelfont cmbx10
OK; any more? grayfont black
OK; any more?
After the ¬nal carriage return, GFtoDVI does its normal thing, ignoring font speci¬ca-
tions in the ¬le that con¬‚ict with those just given.
330 Appendix H: Hardcopy Proofs


2. Gray fonts. A proof diagram constructed by GFtoDVI can be regarded as an array Gray fonts
of rectangles, where each rectangle is either blank or ¬lled with a special symbol that
we shall call ˜ ™. A blank rectangle represents a white pixel, while represents a black
pixel. Additional labels and reference lines are often superimposed on this array of
rectangles; hence it is usually best to choose a symbol that has a somewhat gray
appearance, although any symbol can actually be used.
In order to construct such proofs, GFtoDVI needs to work with a special type
of font known as a “gray font”; it™s possible to obtain a wide variety of di¬erent sorts of
proofs by using di¬erent sorts of gray fonts. The next few paragraphs explain exactly
what gray fonts are supposed to contain, in case you want to design your own.
The simplest gray font contains only two characters, namely and another
symbol that is used for dots that identify key points. If proofs with relatively large
pixels are desired, a two-character gray font is all that™s needed. However, if the pixel
size is to be relatively small, practical considerations make a two-character font too
ine¬cient, since it requires the typesetting of tens of thousands of tiny little characters;
printing-device drivers rarely work very well when they are presented with data that is
so di¬erent from ordinary text. Therefore a gray font with small pixels usually has a
number of characters that replicate in such a way that comparatively few characters
actually need to be typeset.
Since many printing devices are not able to cope with arbitrarily large or
complex characters, it is not possible for a single gray font to work well on all machines.
In fact, must have a width that is an integer multiple of the printing device™s units
of horizontal and vertical positioning, since rounding the positions of grey characters
would otherwise produce unsightly streaks on proof output. Thus, there is no way to
make the gray font as device-independent as normal fonts of type can be.
This understood, we can now take a look at what GFtoDVI expects to see in a
gray font. The character always appears in position 1. It must have positive height h
and positive width w; its depth and italic correction are ignored.
Positions 2“120 of a gray font are reserved for special combinations of ™s and
blanks, stacked on top of each other. None of these character codes need be present in
the font; but if they are, the slots must be occupied by characters of width w that have
certain con¬gurations of ™s and blanks, prescribed for each character position. For
example, position 3 of the font should either contain no character at all, or it should
contain a character consisting of two ™s, one above the other; one of these ™s should
rest on the baseline, and the other should appear immediately below.
It will be convenient to use a horizontal notation like ˜ ™ to stand for a
vertical stack of ™s and blanks. The convention will be that the stack is built from
bottom to top, and the topmost rectangle should sit on the baseline. Thus, ˜ ™ stands
actually for a character of height h and depth 4h that looks like this:
←’ baseline


We use a horizontal notation in this discussion instead of a vertical one because column
vectors take too much space, and because the horizontal notation corresponds to binary
numbers in a convenient way.
Positions 1“63 of a gray font are reserved for the patterns , , , , , and
so on up to , just as in the normal binary notation of the numbers 1“63, with
™s substituted for 1™s and blanks for 0™s. Positions 64“70 are reserved for the special
Appendix H: Hardcopy Proofs 331


patterns , , , , , , of length seven; positions 71“78 charlist
fontdimen
are, similarly, reserved for the length-eight patterns through . The length-
font slant
nine patterns through are assigned to positions 79“87, the length-ten
patterns to positions 88“97, the length-eleven patterns to positions 98“108, and the
length-twelve patterns to positions 109“120.
Position 0 of a gray font is reserved for the “dot” character, which should
have positive height h and positive width w . When GFtoDVI wants to put a dot
at some place (x, y) on the ¬gure, it positions the dot character so that its reference
point is at (x, y). The dot will be considered to occupy a rectangle whose corners are
at (x ± w , y ± h ); the rectangular box for a label will butt up against the rectangle
enclosing the dot.
All other character positions of a gray font (namely, positions 121“255) are
unreserved, in the sense that they have no prede¬ned meaning. But GFtoDVI may
access them via the charlist feature of tfm ¬les, starting with any of the characters in
positions 1“120. In such a case each succeeding character in a list should be equivalent
to two of its predecessors, horizontally adjacent to each other. For example, in
charlist 53: 121: 122: 123
character 121 will stand for two 53™s, character 122 for two 121™s (i.e., four 53™s), and
character 123 for two 122™s (i.e., eight 53™s). Since position 53 contains the pattern
, character 123 in this example would have height h, depth 5h, and width 8w, and
it would stand for the pattern
←’ baseline


Such a pattern is, of course, rather unlikely to occur in a gf ¬le, but GFtoDVI would be
able to use if it were present. Designers of gray fonts should provide characters only
for patterns that they think will occur often enough to make the doubling worthwhile.
For example, the character in position 120 ( ), or whatever is the tallest stack
of ™s present in the font, is a natural candidate for repeated doubling.
Here™s how GFtoDVI decides what characters of the gray font will be used,
given a con¬guration of black and white pixels: If there are no black pixels, stop.
Otherwise look at the top row that contains at least one black pixel, and the eleven
rows that follow. For each such column, ¬nd the largest k such that 1 ¤ k ¤ 120
and the gray font contains character k and the pattern assigned to position k appears
in the given column. Typeset character k (unless no such character exists) and erase
the corresponding black pixels; use doubled characters, if they are present in the gray
font, if two or more consecutive equal characters need to be typeset. Repeat the same
process on the remaining con¬guration, until all the black pixels have been erased.
If all characters in positions 1“63 are present, this process is guaranteed to
take care of at least six rows each time; and with characters 64“120 as well, it usually
takes care of twelve, since all patterns that contain at most one “run” of ™s are present.
Some of the fontdimen parameters discussed in Appendix F are important in
gray fonts. The font slant value s, if nonzero, will cause GFtoDVI to skew its output;
in this case the character will presumably be a parallelogram with a corresponding
slant, rather than the usual rectangle. ™s coordinate (x, y) will appear in
physical position (xw + yhs, yh) on the proofsheets. (This is appropriate for proo¬ng
unslanted fonts whose pixels will become slanted by mechanical obliquing.)
332 Appendix H: Hardcopy Proofs


Parameter fontdimen 8 of a gray font speci¬es the thickness of rules that go font normal space
font quad
on the proofs. If this parameter is zero, TEX™s default rule thickness (0.4 pt) will be
font x height
used. The other parameters of a gray font are ignored by GFtoDVI, but it is conventional grayf.mf
to set font normal space and font quad to w, font x height to h. large pixels
pix picture
For best results the designer of a gray font should choose w and h so that the pix wd
user™s dvi-to-hardcopy software will not make any rounding errors. Furthermore, the pix ht
rep
dot should be an even number 2m of pixels in diameter, and the rule thickness should
lightweight
work out to an even number 2n of pixels; then the dots and rules will be centered on dotsize
the correct positions, in the common case of integer coordinates. Gray fonts are almost font identi¬er
gray
always intended for particular output devices, even though ˜dvi™ stands for “device
black
independent”; we use dvi ¬les for proofs chie¬‚y because software to print
dvi ¬les is already in place.
The program for a fairly versatile gray font generator, called
˜grayf.mf™, appears on the next few pages. It should be invoked by a parameter
¬le that establishes values of several quantities:
If large pixels is of type boolean, only 15 characters will be generated; oth-
erwise there will be 123.
If pix picture is of type picture, it should be the desired pixel image ˜ ™,
and in this case pix wd and pix ht should be the width and height in pixels.
Otherwise a default gray pixel pattern will be used.
If rep is known, it should be a positive integer; the default pixel pattern will
be replicated so that the ¬nal proofs will be rep times bigger than usual, and
the pattern will be clipped slightly at the edges so that discrete pixels can be
seen plainly.
If lightweight is of type boolean, the default pixel pattern will be only half
as dark as usual.
If dotsize is known, it should be the diameter of the special dot character, in
pixel units.
The font identi¬er should be speci¬ed.
(The rep and lightweight options are ignored if pix picture is explicitly given.) Since
gray fonts are inherently device-dependent, we do not start with “sharp” dimensions
as in normal fonts; we go backwards and compute the sharp units from pixel units.
The name of each gray font should include the name of the device for which it
is intended. (A “favorite” proof device can also be chosen at each installation, for which
the alternate font names ˜gray™ and ˜black™ are valid; these installation-dependent fonts
are the defaults for proof mode and smoke mode.)
Here, for example, is a suitable parameter ¬le ˜graycheap.mf™, which generates
a vanilla-¬‚avored gray font for the hypothetical cheapo printer:
% Gray font for Cheapo with proofsheet resolution 50 pixels per inch
if mode<>cheapo: errmessage "This file is for cheapo only"; fi
font_identifier "GRAYCHEAP";
input grayf
(The proofsheet resolution will be 50 per inch, because cheapo has 200 pixels per
inch, and the default pix picture in grayf will be four pixels square in this case.)
If the default pixel pattern turns out to be such a dark gray that the labels and
rules are obscured, the statement ˜boolean lightweight™ should be added. A solid
Appendix H: Hardcopy Proofs 333


black font with slightly higher-resolution images can be generated by the following ¬le tfm
˜blackcheap.mf™:
% Black font for Cheapo with proofsheet resolution 66.7 pixels per inch
if mode<>cheapo: errmessage "This file is for cheapo only"; fi
picture pix_picture; pix_wd := pix_ht := 3;
pix_picture := unitpixel scaled 3;
font_identifier "BLACKCHEAP";
input grayf
And here is a ¬le ˜graycheap5.mf™ that generates a gray font suitable for studying large
proofs of low-resolution characters:
% Gray font for Cheapo with proofsheet resolution 10 pixels per inch
if mode<>cheapo: errmessage "This file is for cheapo only"; fi
rep=5; boolean large_pixels;
font_identifier "GRAYCHEAP";
input grayf
Now let™s look at the program ¬le ˜grayf.mf™ itself. It begins with a simple
test to ensure that mag and rep are positive integers, if they™re known; then comes
some less obvious code that handles magni¬cation in a nonstandard way:
% More-or-less general gray font generator
% See Appendix H of The METAFONTbook for how to use it
forsuffixes m = mag,rep:
if unknown m: m := 1;
elseif (m<1) or (m<>floor m):
errmessage "Sorry, " & str m & " must be a positive integer";
m := 1; fi endfor
mg := mag; mag := 1; mode_setup;
if mg>1: hppp := hppp*mg; vppp := vppp*mg;
extra_endchar:=
"if charcode>0:currentpicture:=currentpicture scaled mg;fi"
& extra_endchar; fi;
This circumlocution is the easiest way to guarantee that the tfm ¬le will be completely
una¬ected by magni¬cation.
The next part of grayf computes the pixel representation, pix picture .
if picture pix_picture: rep := 1;
cull pix_picture keeping (1,infinity);
else: for z=(0,2),(1,0),(2,3),(3,1):
fill unitsquare shifted z; endfor
if not boolean lightweight:
addto currentpicture also
currentpicture rotated 90 xscaled -1; fi
if unknown scale: scale := max(1,round(pixels_per_inch/300)); fi
pix_wd := pix_ht := 4scale;
334 Appendix H: Hardcopy Proofs


if rep>1: picture pix; charlist
chardx
currentpicture := currentpicture shifted-(1,1); pix := currentpicture;
charwd
for r=1 upto rep-1: addto currentpicture also pix shifted(4r,0); endfor charht
cullit; pix := currentpicture;
for r=1 upto rep-1: addto currentpicture also pix shifted(0,4r); endfor
unfill unitsquare xscaled 4rep yscaled 2 shifted-(1,1);
unfill unitsquare yscaled 4rep xscaled 2 shifted-(1,1); cullit; fi
picture pix_picture; pix_picture := currentpicture scaled scale;
pix_wd := pix_ht := 4scale*rep; fi
The lightweight pattern has 4 of every 16 pixels turned on; the normal pattern has
twice as many.
Character 0 is the dot, which is quite simple:
def # = *72.27/pixels_per_inch enddef;
if unknown dotsize: dotsize := 2.5pix_wd/rep; fi
beginchar(0,1.2dotsize#,1.2dotsize#,0);
fill fullcircle scaled dotsize scaled mg; endchar;
The special coding scheme of gray fonts is implemented next:
numeric a[]; newinternal b,k;
def next_binary =
k := 0; forever: if k>b: a[incr b] := 0; fi
exitif a[k]=0; a[k] := 0; k := k+1; endfor
a[k] := 1 enddef;
def next_special_binary =
if a[0]=1: for k=0 upto b: a[k] := 0; endfor a[incr b]
else: k := 0; forever: exitif a[incr k]=1; endfor
a[k-1] fi := 1 enddef;
def make_char =
clearit; next_binary;
for k=0 upto b: if a[k]=1:
addto currentpicture also pix_picture shifted(0,-k*pix_ht); fi endfor
charcode := charcode+1; chardp := b*charht;
scantokens extra_endchar; shipout currentpicture enddef;
Now we are ready to generate all the pixel characters.
charwd := pix_wd#; charht := pix_ht#; chardx := pix_wd*mg;
b := -1;
if boolean large_pixels:
for k=1 upto 7: make_char; charlist k:k+120; endfor
charcode := 120; b := -1;
addto pix_picture also pix_picture shifted (chardx,0);
charwd := 2charwd; chardx := 2chardx;
for k=1 upto 7: make_char; endfor
else: for k=1 upto 63: make_char; endfor
let next_binary = next_special_binary;
for k=64 upto 120: make_char; endfor
Appendix H: Hardcopy Proofs 335


for k=121,122: charcode := k; aspect ratio
Slant fonts
addto currentpicture also currentpicture shifted (chardx,0);
charht
charwd := 2charwd; chardx := 2chardx; tfm
charwd
scantokens extra_endchar; shipout currentpicture; endfor
font slant
charlist 120:121:122; fi
The program closes by establishing fontwide parameters:
font_coding_scheme "GFGRAY";
font_size 8(pix_wd#);
font_normal_space pix_wd#;
font_x_height pix_ht#;
font_quad pix_wd#;
fontdimen 8: if known rulethickness: rulethickness
else: pix_wd#/(2rep) fi;
bye.

<< . .

. 40
( : 45)



. . >>