2

In "The Concept of a Metafont" Donald E. Knuth explores in a visual way the possibilities of parametric variations. But I have some questions:

  • Did he used TeX to typeset the article?
  • Does TeX allows continuous variation of parameters? Sometimes, even in the same paragraph the changes letter to letter are visible. How is the communication between Metafont and TeX processed in this cases?

Thank you

  • LuaTeX has support for MetaPost fonts (at least in ConTeXt). See pragma-ade.nl/general/manuals/fonts-mkiv.pdf (search for "punknova") – Henri Menke Aug 29 at 8:35
  • Thank you, Henri Menke. But, this example has to do with choosing alternates. It is the same process like in Knuth's article? In page 15 he has one paragraph with continuous variation from start to end. Every single letter is different. How does he do this? Does TeX allows this? How? (probably its a good ideia to say that I'm not familiarized with code language) – Ana Fernandes Aug 29 at 9:19
  • 1
    Welcome! Yes, Knuth used TeX to typeset the article. If you mean the “The LORD is my shepherd…” example on page 15, it is done as an insert, i.e. similar to inserting a figure. Of course, this figure was itself done (separately) with TeX (superficially), but with some trickery like creating a special “font” just for that figure, in which the kth character in the font was the kth character desired in the output. If you know exactly what you want, you can do anything. :-) – ShreevatsaR Aug 29 at 10:00
  • 1
    As far as I know, there isn't any generally available version of TeX that is closely coupled with TeX to make such interaction available. There is an implementation of LuaTeX that has Metapost as an available library, but that's not quite the same thing. There was a paper at TUG 2019 that included a demonstration of an interactive TeX/MF hybrid that might make what you describe possible; however, that produces output with bitmap fonts, so would not be useful unless the image will always appear on a surface matching the resolution at which it was created. – barbara beeton Aug 29 at 13:26
  • 1
    For Metafont, a font is just a collection of (up to) 256 pictures (glyphs). (So think something like “Computer Modern Italic at 8pt”, not “Computer Modern”.) In the example, Knuth created a “font” whose 256 characters were “T (with certain params)”, ”h (with certain params)”, “e (with certain params)”, “L (with certain params)” etc. (Switching to a new font after every 256 slots.) For example, the 3 “e”s in the first line are simply 3 different glyphs in the same font. But TeX can directly induce the variations, as (in TeX Live etc) if a font is missing Metafont will be invoked to create it. – ShreevatsaR Aug 29 at 16:39
6

Knuth's The Concept of a Meta-Font (abstract, PDF) is not just a paper but a performance, as he uses the visual appearance of each paragraph itself to illustrate the ideas in it. Between two particular paragraphs is a separate page containing a setting of Psalm 23, which also marks a transition in the paper itself from one font to another:

concept of a metafont, psalm 23

Here, the characters progressively get larger (even within the same line) in width (“em width”) and height (“x-height”) while retaining the same “h-height” (ascender height I think).

The paper was of course typeset with TeX, including this insert.

To show how it was or could be done, while keeping it simple (for my own sake, being not very familiar with Metafont), I'll use a particularly simple font containing just the numerals 0–9, from this question.

No tricks

Just to repeat the example from the other question (just being included here to make it easier to understand the later examples): you can put the following definition of the font in a file called postal.mf:

leftgap := 0.1;
rightgap := 0.1;
penthickness := 0.08;
midlineheight := 0.5;
toplineheight := 1;
width# := 9pt#;
height# := 10pt#;

mode_setup;
def begincchar(expr c) =
  beginchar(c, width#, height#, 0);
    t := toplineheight * h;
    m := midlineheight * h;
    a := leftgap * w;  b := w - rightgap * w;
    z1=(a,t); z2=(b,t);
    z3=(a,m); z4=(b,m);
    z5=(a,0); z6=(b,0);
    pickup pencircle scaled (penthickness * w);
    penlabels(1,2,3,4,5,6);
enddef;

def drawzero  = draw z2--z1--z5--z6--cycle; endchar; enddef;
def drawone   = draw z3--z2--z6; endchar; enddef;
def drawtwo   = draw z1--z2--z4--z5--z6; endchar; enddef;
def drawthree = draw z1--z2--z3--z4--z5; endchar; enddef;
def drawfour  = draw z1--z3--z4; draw z2--z6; endchar; enddef;
def drawfive  = draw z2--z1--z3--z4--z6--z5; endchar; enddef;
def drawsix   = draw z2--z3--z5--z6--z4--z3; endchar; enddef;
def drawseven = draw z1--z2--z3--z5; endchar; enddef;
def draweight = draw z2--z1--z5--z6--cycle; draw z3--z4; endchar; enddef;
def drawnine  = draw z4--z3--z1--z2--z4--z5; endchar; enddef;

begincchar("0"); drawzero;
begincchar("1"); drawone;
begincchar("2"); drawtwo;
begincchar("3"); drawthree;
begincchar("4"); drawfour;
begincchar("5"); drawfive;
begincchar("6"); drawsix;
begincchar("7"); drawseven;
begincchar("8"); draweight;
begincchar("9"); drawnine;
end

and then use the font in your .tex file:

\font\postalfont=postal
$\pi$ is roughly three point {\postalfont 14159265} in value.
\bye

to get:

simple case

Manually defining the font

For the "The LORD is my shepherd" example, Knuth defined a special “font” whose 256 characters were “T (with certain params)”, ”h (with certain params)”, “e (with certain params)”, “L (with certain params)” and so on. (Switching to a new font after every 256 slots.) For example, the 3 “e”s in the first line are simply 3 different glyphs in the same font. Here's an example of something similar with our postal-digits font. This time, after deleting anything leftover from last time (postal.*), put the following in your postal.mf font:

leftgap := 0.1;
rightgap := 0.1;
penthickness := 0.08;
midlineheight := 0.5;
toplineheight := 1;
width# := 9pt#;
height# := 10pt#;
scale := 1;

mode_setup;
def begincchar(expr c) =
  beginchar(c, width# * scale, height# * scale, 0);
    t := toplineheight * h;
    m := midlineheight * h;
    a := leftgap * w;  b := w - rightgap * w;
    z1=(a,t); z2=(b,t);
    z3=(a,m); z4=(b,m);
    z5=(a,0); z6=(b,0);
    pickup pencircle scaled (penthickness * w / scale);
    penlabels(1,2,3,4,5,6);
enddef;

def drawzero  = draw z2--z1--z5--z6--cycle; endchar; enddef;
def drawone   = draw z3--z2--z6; endchar; enddef;
def drawtwo   = draw z1--z2--z4--z5--z6; endchar; enddef;
def drawthree = draw z1--z2--z3--z4--z5; endchar; enddef;
def drawfour  = draw z1--z3--z4; draw z2--z6; endchar; enddef;
def drawfive  = draw z2--z1--z3--z4--z6--z5; endchar; enddef;
def drawsix   = draw z2--z3--z5--z6--z4--z3; endchar; enddef;
def drawseven = draw z1--z2--z3--z5; endchar; enddef;
def draweight = draw z2--z1--z5--z6--cycle; draw z3--z4; endchar; enddef;
def drawnine  = draw z4--z3--z1--z2--z4--z5; endchar; enddef;

begincchar(0); "1"; scale := scale*0.95; drawone;
begincchar(1); "4"; scale := scale*0.95; drawfour;
begincchar(2); "1"; scale := scale*0.95; drawone;
begincchar(3); "5"; scale := scale*0.95; drawfive;
begincchar(4); "9"; scale := scale*0.95; drawnine;
begincchar(5); "2"; scale := scale*0.95; drawtwo;
begincchar(6); "6"; scale := scale*0.95; drawsix;
begincchar(7); "5"; scale := scale*0.95; drawfive;
begincchar(8); "3"; scale := scale*0.95; drawthree;
begincchar(9); "5"; scale := scale*0.95; drawfive;
begincchar(10);"8"; scale := scale*0.95; draweight;
begincchar(11);"9"; scale := scale*0.95; drawnine;
begincchar(12);"7"; scale := scale*0.95; drawseven;
begincchar(13);"9"; scale := scale*0.95; drawnine;
begincchar(14);"3"; scale := scale*0.95; drawthree;
end

Observe the last part of the above, where we modify scale before drawing the characters: the earlier font put a glyph for the numeral “1” at the slot corresponding to the ASCII code for “1” (namely, position 49 in the font), as normal fonts do. In this case, instead we've defined the font to have a certain kind of "1" as the glyph in its earliest slot (position 0), then the next slot (position 1) has a certain kind of "4", then the next slot (position 2) has a different kind of "1", and so on — we've defined the characters based on what we want in the output.

Starting with the .mf file, you can first run Metafont on it (with the right arguments, which I can't figure out right now) to generate the glyphs and font metrics (.tfm file), then run the following .tex file that uses it:

\font\postalfont=postal
$\pi$ is roughly three point {\postalfont \char0 \char1 \char2 \char3 \char4 \char5 \char6 \char7 \char8 \char9 \char10 \char11 \char12 \char13 \char14} in value.
\bye

scaling, done manually

Here in the .tex file we manually wrote out "\char0 \char1..." etc to be explicit, but of course TeX has macros for making it easier. Not only that, but modern TeX distributions will automatically invoke Metafont if a font is not found. Also, TeX can write to files. Using all that, we can get the following.

Automatic, single-file solution

Delete anything leftover from earlier, and create a single .tex file containing:

\newwrite\fontfile
\immediate\openout\fontfile=postal.mf
\catcode`\^^M=\active \def^^M{^^J} \catcode`\#=12 \immediate\write\fontfile{
leftgap := 0.1;
rightgap := 0.1;
penthickness := 0.08;
midlineheight := 0.5;
toplineheight := 1;
width# := 9pt#;
height# := 10pt#;
scale := 1;

mode_setup;
def begincchar(expr c) =
  beginchar(c, width# * scale, height# * scale, 0);
    t := toplineheight * h;
    m := midlineheight * h;
    a := leftgap * w;  b := w - rightgap * w;
    z1=(a,t); z2=(b,t);
    z3=(a,m); z4=(b,m);
    z5=(a,0); z6=(b,0);
    pickup pencircle scaled (penthickness * w / scale);
    penlabels(1,2,3,4,5,6);
enddef;

def drawzero  = draw z2--z1--z5--z6--cycle; endchar; enddef;
def drawone   = draw z3--z2--z6; endchar; enddef;
def drawtwo   = draw z1--z2--z4--z5--z6; endchar; enddef;
def drawthree = draw z1--z2--z3--z4--z5; endchar; enddef;
def drawfour  = draw z1--z3--z4; draw z2--z6; endchar; enddef;
def drawfive  = draw z2--z1--z3--z4--z6--z5; endchar; enddef;
def drawsix   = draw z2--z3--z5--z6--z4--z3; endchar; enddef;
def drawseven = draw z1--z2--z3--z5; endchar; enddef;
def draweight = draw z2--z1--z5--z6--cycle; draw z3--z4; endchar; enddef;
def drawnine  = draw z4--z3--z1--z2--z4--z5; endchar; enddef;
} \catcode`\^^M=5 \catcode`\#=6

\newcount\n
\n=0
\newcount\m
\m=0

\def\name#1{%
  \ifcase#1
    zero
    \or one%
    \or two%
    \or three%
    \or four%
    \or five%
    \or six%
    \or seven%
    \or eight%
    \or nine%
    \fi
}
\def\addchar#1{%
  \immediate\write\fontfile{
    begincchar(\number\n); "#1"; scale := scale*0.95; draw\name#1;}%
  \advance\n by 1}

% Add the next character as char \n to the current font, and repeat
% When \relax is seen, define \postalfont and print chars 0 to \n from it.
\def\vanishing#1{%
  \ifx#1\relax
  \immediate\write\fontfile{end}%
  \immediate\closeout\fontfile
  \font\postalfont=postal
  \postalfont
  \loop \char\m \advance\m by 1 \ifnum\m<\n \repeat
  \tenrm
  \ \else%
  \addchar#1%
  \expandafter\vanishing\fi}

$\pi$ is roughly three point \vanishing 141592653589793\relax in value.
\bye

Everything before the last two lines is setup, which defines some macros and writes out the initial part of the .mf file from TeX itself. The last two lines is the actual usage: from TeX you can write \vanishing 141592653589793\relax and "automatically" get the corresponding characters produced according to varying parameters. The output is the same as before:

automatic

(Of course this is only proof-of-concept and will fail under various conditions and I know nothing about font design and there are much better ways to do this, but I think this gives you some idea.)

  • Thank you!!! @ShreevatsaR – Ana Fernandes Sep 2 at 15:59
  • @AnaFernandes You're welcome. Maybe I didn't answer the actual question: In principle METAFONT is written as a batch program, to run and generate its output before TeX can use it. In practice, as TeX and METAFONT sources are basically programs, it is possible with some trickery (as above) to communicate between them in many surprising ways. See also (1) mplib in LuaTeX, which turns MetaPost (which is almost METAFONT) into a library and allows even more kinds of communication and calling it from TeX, (2) TikZ etc., (3) this site with interactive Meta-fonts. – ShreevatsaR Sep 2 at 16:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.