Algorithmic glyph outline creation

Ledrug's picture

I'm currently toying with the idea of generating glyph outlines to create a font family in a parametric way. Right now, as a test, I have a program that defines the shapes of the 26 latin characters both lc and uc (and smcp, not shown), using various parameters such as character widths, x/cap/asce/desc hights, nominal horizontal/vertical stroke widths, etc. Attached is the result of nine fonts with varying weight which in turn defines stroke widths and "squareness". Most other things can be changed, too, the only thing fixed is the fundamental composition of each glyph ("b" is conceptually a vertical stroke with an uneven ellipse; this kind of things are, I guess, the design element). Ultimately, I want a set of programs defining a font such that by tuning some parameters, varying but consistent set of fonts can be created without further human intervention.

Now, the result is obviously not perfect, and I meant to as for suggestions here. But lacking any formal training in typography, I'm not sure what to ask. I'll start with broad ones:
1. Has anyone tried this sort of algorithmic approach before? (Donald Knuth obviously has, but I'm not a big fan of the resulting Computer Modern family; MetaFont is also a pretty horrible language to program in.) Is it feasible to some extent?
2. As far as the example image goes, what are the things I did completely wrong, from a designer's point of view?

[Edit: added a pdf. You can probably extract the fonts from it with the right tools.]
[Edit2: updated pdf]

AttachmentSize
x.png280.09 KB
dln.png34.32 KB
fonttest.pdf60.2 KB
HVB's picture

How does your approach differ from Adobe's (now abandoned) Multiple Masters?

Ledrug's picture

MMM as I understand, has a number of axes, each representing a continuously variable parameter, with a (hand-crafted) font sitting at either end of each axis, and the font engine interpolates in between these fonts. I have a small program defining glyph outlines for each char, which in theory can do much more than interpolation: whatever the underlying programming language (Perl here) can do, can be done.

MMM to me seem to have two important limitations: 1) I can't see how interpolation can give enough control to finer shape changes; 2) Correct me if I'm wrong, but if you have N parameters, MMM requires 2^N predefined glyph sets to work with, so if you have say 6 parameters, you'd need to make 64 fonts by hand, which rather defeats the point of letting computers do all the work.

froo's picture

Can you show how letters "dln" of the two extreme weights look?

Ledrug's picture

"dln" attached at the top post (don't know how to insert image here). Why them three letters?

hrant's picture

Great topic.

Related threads:
http://www.typophile.com/node/73827
http://www.typophile.com/node/86431

Great news that you can't stand Computer Modern.
More soon.

hhp

sgh's picture

Nice! What system are you using to generate the glyphs? I would be interested in seeing the code.

I have used MetaType1 (a library of routines written in MetaPost for creating Type 1 fonts)---see Aurulent Sans. However, I found that MetaPost was not particularly pleasant to program in.

I have since been working on using Python in Fontforge to create glyphs. That part all works fine, but I've been more recently thinking about more fundamental issues about the construction of glyphs: see Aligning points on outline of straight to curved stroke, Logical tapered joints on expanded paths, generic sans, and Spiro. I think algorithmic generation of glyphs encourages a different exploration of glyph features than usual graphical tools do.

Best wishes,
Stephen

oldnick's picture

I would have to say “Very impressive.” The results are vastly superior to the “Make Bold” options currently available in FontLab and Fontographer. Even if the resulting glyphs aren't 100% perfect, your routines do a yeoman's share of the heavy lifting. An auteur could then finesse the results as he or she sees fit.

Keep up the good work, and keep us posted on progress.

Ledrug's picture

I've read all of the linked threads above (I've read pretty much the whole design board before I registered). They are no doubt interesting topics, though my problem is not in math, but rather in design: I can have a program draw anything, if I know what I want to draw.

My code is heavily experimental, and is no more readable than a good MetaPost or MetaFont. Here's the function responsible for drawing "O", "o" and "Osmall" (and will be called by say, "Oslash"):

sub shape_o {
	my $w = round(shift());
	my $h = shift;
	my $cap = shift // 0;

	set_brush(0, $cap);
	$hw = round($hw);
	$vw = round($vw);

	my ($x0, $x1) = set_stroke(0, $w, $vw + $thicken, $bearing_bow);
	my ($x2, $x3) = set_stroke(0, $w, $vw + $thicken, $w - $bearing_bow);

	my $cx = round(($x1 + $x2) / 2);
	my $cy = round($h / 2);

	path	->ellipse($cx, $cy, $cx - $x0, $h/2 + $os, $rout)
		->ellipse($cx, $cy, $x1 - $cx, $h/2 + $os - $hw, $rin),
	$w,
	hhint=>[-$os, -$os + $hw, $h + $os - $hw, $h + $os],
	vhint=>[$x0, $x1, $x2, $x3],
	aaanchor=>[round($w/2), $h]
}

$w, $h and $cap are passed in params specifying glyph width, glyph height and whether it's a capital letter (capitals have slightly wider v-strokes than lc or smcp). set_brush sets nominal h- and v-stroke widths ($hw and $vw); set_stroke sets the positions of the left and right arcs. Here $bearing_bow is a family-wide parameter, saying how far a bow-shaped stroke should be from the edge of the glyph, though the stroke actually straddles this position, so the actual bearings will be smaller than this nominal value, more so for heavier weights, in order that heavy weights will have smaller white spaces both between chars and inside each char.

path->ellipse(...) creates a path with a psuedo elliptical shape given center x, center y, radius x and radius y, plus two optional "roundness" factors. The result is a true ellipse if the roundness is 4/3 (sqrt(2)-1), but currently I'm using slightly larger values to make bows more squarish.

The function returns a list of things: the path consisting of two "ellipses" of opposite winding; the glyph width which includes left and right bearing; hori/vert hints ($os is the vertical overshoot); anchor point of typical accent-above. The last one is going to be used for attaching accute, grave, etc., though right now only "i" and "j" use them (the "i" is really a composite of "dotlessi" plus "dotaccent"). This function is called by a master builder program when needed, and returned values are put into a list, later written out to a .sfd file (FontForge format), so I can either open it to have a look, or convert it to .otf via command line.

I can make the whole system work, because I wrote every piece of code involved in defining the glyphs; it would be nice if I could make it more usable for anyone else, but for that I need to know if what I do makes sense (cf. lack of typographic training). Right now I'd really appreciate it if someone can tell me stuff like "your uppercase letters needs more white space on either side" or "your 'X' is too thin on the right leaning stroke"; the only thing obvious to me is the fonts should be kerned, but I'd rather get the natural spacing of each character right before doing that.

[EDIT: tag leak]

froo's picture

Why them ["dln"] three letters?
I wanted to see the details of the terminals magnified. Now I understand the source of those changes at the Black serifs, but I personally feel lack of a similar approach in places where the arches join to the stems. The lowercase Black "u" is a good example here; there is too much ink in it. In other words - you change modulation of serifs extremally, while the arches stay pasive.

Anyway, the uppercase Black R and K are the wicked problem. They should be corrected by hand, but I feel intuitively, that an algorithm responsible for changing stroke direction (to introduce lights into dark places), should do the trick to some extent.

Ledrug's picture

@froo:
Too much ink it was. I changed how the joints work for the "u"s, but I don't want to break the symmetry of the bows on "d", so instead the tails are now thinner when needed. "R" has its slanted stroke steeper and more the the right at hearier weights, so it won't run into the vertical stroke now. As to "K", I took the cop-out approach: just made them wider as weight goes up, which naturally leaves more white space. The pdf at the top post is updated.

"b", "p" and "q" all have similar arc-to-vertical joints, I'm curious what you think about those?

froo's picture

The K is really bad now, there is too much of A in it. Anyway, the letters e and c in all sets look odd: they're much wider than o's, like they were taken from an other typeface. I like things that happen to the upper parts of B,D,P etc - I have an impression that fine-tuned source details stay fine, while bugs grow. Probably there is some kind of a boundary that the outline method has, and cannot pass further... There is always a given skeleton, which can be split in parts, inside every outline; than, the outline (contrast, modulation etc) is a secondary issue, like a body. One can refine his figure only to a certain degree, allowed by shape of his bones.

dberlow's picture

"...so if you have say 6 parameters, you'd need to make 64 fonts by hand, which rather defeats the point of letting computers do all the work."

Letting computers do all the work is the goal? Geeze, I really missed the boat on that one!

Why not ask some computers what's wrong with your design?

;)

Ledrug's picture

@froo: If you think the "K" is bad, wait till you see the ampersand I currently have, heh. As an amateur's first experiment, I'm not surprised there would be more bad glyphs than good ones; although your impression about "a", "e" and "o" did surprise me: e and o are always the same width, a is actually about 5-10% narrower. If a and e appear visually wider, would that be because of the open hooks or the inner strokes?

@dberlow: Besides work, what else are computers good for? We can make them do as much work as we understand the subject matter, and this experiment is to find out how much I understand it; if you give some pointer, I'll learn more, and the computer can do more. It's highly probable that any automated font generation will always require some final human touch -- or it will cease to be an artform -- but it wouldn't hurt if computers can be made to do more stuff corretly to begin with. I've openly stated my inexperience, there's no need to treat me like a moron. Even if I were indeed one, making fun of it doesn't really help anyone, does it?

hrant's picture

In fact parametric/generative font design is a higher form of design that merely making instances of glyphs.

hhp

froo's picture

@Ledrug:
I describe my impression - for me, personally, c and also e look wider than o, although they all have the same widths. Yes, that is caused by the open hooks. (So we have this kind of situation here, where a type designer [no matter if he were right or wrong] would try to adjust these letters - add some ink here and there, or make them narrower).

dberlow's picture

Hrant: "In fact parametric/generative font design is a higher form of design tha[n] merely making instances of glyphs."

That can be a fact. But as one can see from this example, it's not always true in practice. I think an expert make of a per size/device font instance can be a much higher form of design than any novice weight axis.

Being one of the few, of not the only designer ever to chase down all the corners of a 6-axes GX font, and having had a close working relationship to the three K's of parametric scaling, (Knuth, Karow and Kaasila), I can tell this is likely going nowhere for lack of sense of humor, if nothing else. :)

Ledrug's picture

Surely a joking comment with a smug sense of superiority only comes with success, and not laughing at it is a sign of a novice's failure. Only thing is, like I said, it doesn't help anybody. Or maby this is how "ask a silly question, get a silly answer" works, I guess it was my fault to dare to ask and want a straight answer after all. If so, my apologies.

hrant's picture

An example is an example. Everybody's first font looks horrible, hence is not a good predictor of how successful the journey will be. This is especially true of something that has virtually no precedent.

There are limits to what computers can do, and limits to what humans can do. Type design so far has pushed much deeper into the latter than the former, and to me this is a good attempt to address that imbalance.

hhp

fujito's picture

"MetaFont is also a pretty horrible language to program in"

Really? Your program snippet "sub shape_o" is not much different to METAFONT coding. Writing macros in METAFONT is a bit unusual compared to other programming languages, but letter shapes can be defined quite elegant.

Have you ever tried to outline glyphs in the following way:

METAFONT code (whitout any pens) --> processed by METAPOST --> Glyphs written to EPS --> EPS imported to a sfd-file by python-fontforge --> postprocessing with python-fontforge or fontforge

This is a reliable way. Of course you can easily improve it (eg by reading in the tfm file too).

Please think of the fact, that Knuth has been working hard on METAFONT for about 5 years. He has learned much and also documented his mistakes (especially when making the jump from METAFONT79 to METAFONT84). Take a look at them to avoid falling in the same pits. METAFONT is not perfect and it is old but it is easily extensible by macros and it has uptodate successor: METAPOST (which can handle METAFONT code).

-----

Your font is onedimensional at the moment (weight axis). If you would like to add more axis (such as slant or optical size or condensedness axis): Do it now! You will have to consider much more things for your letter constructions.

One simple tip for your letter constructions:
I assume your legs (at the k or R) are defined the following way:
1. Definition of the middle path of the leg
2. Expanding the path to a stroke
Hence, the legs are to close to the vertical stems for bold style. You could do instead something like
1. Definition of the left outlining path of the leg
2. Expanding the path to a stroke

In short: Many paths are probably expanded from the wrong points on.

------------------

Okay, now some compliments:

Your zerodimensional font (whithout weight axis expansion, e. g. medium style) already looks quite good and I suppose this was hard to program.

Details like serifs and endings look quite interesting.

-----

I hope this helps a bit...

vilbel's picture

Very interesting, the only remark I have is that your uppercase k seems to be upside-down.

Syndicate content Syndicate content