An outsider's introduction to Fonts [DRAFT]

Most people who use computers, if interviewed, would probably say that fonts are not really their concern. In fact, they would probably express mild amusement if you went on about how important fonts were .. until they encountered a difficult-to-read typeface on a webpage, that is.

We are immersed in fonts. Yet there is a subtle art to choosing and matching them, and such abilities (or the lack of them), quickly distinguish the professional typographer from tyros like myself! Here is a short webpage that highlights the difficulties the average computer person has with fonts, and tries to make things just a little easier..

What is a 'font'?

Unfortunately, even the word font , used on its own, seems to have acquired different meanings:

  1. "A font family " (for example, Palatino); this includes several styles (eg. plain, italic, bold);
  2. "A font face " (for example, Palatino italic) - a complete set of type of a single style , in all sizes. A typeface .

Because of this ambiguity (and because professionals tend to sneer at you if you don't adhere to their definition), it's probably better to talk about "font families" and "font faces", rather than just using the naked f*** (font) word!

In computer jargon, we often confuse things further by talking about a "digital font", which is usually a data file that contains one or more font faces. (Sometimes you will find that several data files must be taken together, to make up a digital font). Occasionally, you'll find a digital font that contains several faces being referred to as a "font collection".

A digital font describes two main types of information about a particular font face. It tells us about:

  1. Shapes of individual "character images" (glyphs );
  2. Metrics , or how the glyphs relate to one another when printed on the page or shown on the screen.


Glyphs and how they are stored

As we said, a glyph is a character image - the picture that you see, when, for example you look at the letter:

a

Generally, a computer will internally represent a letter or number by a particular numeric code that is stored in a computer file or in the memory of the computer. The code may be limited to a very few choices - the old-fashioned ASCII (American Standard Code for Information Interchange) - or a number from the much more fancy, universal, and up-to-date UNICODE, which many consider infinitely preferable.

When your computer wants to show an "a" on the screen using a particular font face, then it will go to that digital font (stored in memory) and look up the information it needs to draw the particular character. This necessity to look up and draw individual characters is one reason why, even with fast hardware, programs like Microsoft Word are so sluggish at initially displaying text (The other reason is bad programming)!

The real catch is how individual glyphs are described in the computer memory. There is really only one good way of describing a glyph, and that is to use a mathematical description. (The other, obsolete way is to actually have a "bitmap" picture of the character, but the problem with this is that you must either have a zillion different bitmaps for different sizes of "a", or have characters that look OK on one screen, but terrible on another, and print even worse).

The catchy word that goes with describing a glyph is a Bézier curve which is simply a particular (smart) way of describing a curve using a few control points - this makes representation of the curve convenient and surprisingly concise! The equations that are commonly used are:

All the terms second and third order mean is that the equations contain terms such as x 2 (second order), or x 3 (third order). Experts enjoy fussing about which is better, but practically there's not much to choose between the two!

The curves that describe a particular glyph must clearly all join up to make a contour (a closed path). On the one side of a contour there will be an outer region, on the other the inner region of the glyph.

Display

Okay, let's (for the moment) assume that we have a glyph, and we wish to display it on screen. Most computer displays (and certainly, all inexpensive computer displays) use what we call a raster format - the glyph is shown on the screen as a collection of dots, otherwise called pixels . (As an aside, there's even a watertight, registered patent that governs this process of displaying pixels on the screen - needless to say, the patent owners have never exerted their right, nor can one imagine them doing so)!

Once we start translating from a rather abstract mathematical formula to a pattern of dots, things become rather complex. There are several problems:

  1. Pixels (especially screen pixels) are rarely square - the height of a pixel is often quite different from its width.
  2. If you have a small character that you wish to display, and part of the character doesn't quite line up with the pixels, things look terrible
  3. There's a wealth of terminology to further confuse you!

It's common to think of your glyph as fitting onto a grid of little squares - in fact, extremely tiny squares.

A "square tool" is traditionally used to represent coordinates of various parts of a glyph. This is commonly called an EM square . (A capital "M" in typography is an "EM", so you can see how the name came about). The typical EM square size in TrueType fonts is 2048 EM units, while a smaller size is used for type 1 fonts - 1000 units. It might appear to you that type 1 fonts are thus capable of a smaller resolution. Not so, for Adobe in their wisdom (?) allowed for floating point specification of type 1 font coordinates! All rather complex.

The idea behind the EM square is that its height is the intended distance between lines of type in the same type size. The person who designs a glyph can place that glyph anywhere on the EM square - in fact, she can even allow the glyph (in rare circumstances) to extend over the boundaries of the EM square! An EM square is just a convenient fiction, not a confining box.

Note that there are thus several stages in the process of rendering a glyph:

  1. identify the glyph, and access the data defining the curves that include the glyph;
  2. Use these data (which relate to an EM square) and a 'pen' to..
  3. draw the outline of the glyph, using either hinting or byte codes (see below) to fit the glyph to an appropriate pixel grid;
  4. Also sort out matters of spacing between glyphs (and possibly even stretch the glyph slightly to make it fit nicely onto the pixels);
  5. Fill in the outline, creating a bitmap (Termed "scan-line conversion").
  6. Advance the pen to the next pen position (with the position fitted to the pixel grid).

Parts of glyphs

Glyphs are usually made up of strokes (the main parts of the letters) and serifs , the curly bits usually on the ends of the strokes. The serifs are actually quite important, as they generally (and rather surprisingly) make text more legible! (Sans serif fonts are commonly used, but are often less legible. One sure fire way of getting up the nose of a typographer is to use a lot of Sans serif, especially something like Helvetica).

Measuring Things

Different measurement units are used by different typographers, but a common unit is the point which is 1/72 inches. Resolution is commonly measured in DPI or "dots per inch" - in other words, the number of pixels (dots) which fit into one inch. The reason why we use the archaic measure of inches, is that typography goes back an awfully long way, so the inches have acquired a massive and unstoppable inertia! Pica refers to 12 point type (or about 1/6 of an inch).

If you have text of a certain point size, and wish to convert this to a number of pixels, the formula is:

pixel size = point size * resolution / 72

Note that you'll need a lot more spadework before you can actually draw the character, and that because pixels are commonly not square, the horizontal and vertical pixel dimensions will often differ for the same point size.

If you're playing with fonts at a low level, you will also commonly want to convert from EM grid coordinates to pixel coordinates. The formula is:

pixel coordinate = grid coordinate * (pixel size / EM size)


Bézier Curves

Bezier curves are smart . Before we plunge in, let's look at the desirable properties of Bezier curves. We can draw Bezier curves:

Because of these attractive features, they were chosen to form the basis of the PostScript drawing language, the heart of Adobe software. Adobe use the cubic Bezier, which needs just four control points to represent a curve. Before we understand Bezier curves, we need to understand parametric curves. Here goes!

Parametric Curves

Let's consider a plane, and draw a curve on that plane. For several reasons it's often really inconvenient to represent curves using our traditional "y = f(x)" relationship between coordinates in the y and x directions. A smart way is to use a parametric representation of points on the curve. Consider a circle, conventionally represented by:

x 2 + y 2 = r 2

or perhaps:

y = ± ( r 2 - x 2 )1/2

It's clearly cumbersome to calculate y for any point, as we have to take a square root; we must also decide whether y is now positive or negative. Look at the elegant parametric representation:

C x (t) = r * cos(t )
C y (t) = r sin(t )

where t represents an angle between 0 and 360 degrees (2 pi radians).

Note how, with the parametric representation, we calculate x and y separately, each as a function of the parameter t . Let's now consider something very simple - two points, and a line passing through these points. Clearly, there is one unique line that passes through the two points. Similarly, it can be shown that for three points, there is one unique curve:

f(x) = a0.x 2 + a1.x + a2

that passes through those three points. (In fact, we can generalise this to n points, and always find a unique curve of order n-1 that passes through those n points). Now consider a parametric representation of f(x). We surely must be able to say something like:

C x (t ) = a0 x .t 2 + a1 x .t + a2 x
C y (t ) = a0 y .t 2 + a1 y .t + a2 y

All we are doing here is defining the x and y coordinates of a point on the curve, for a parameter t . But look! What are (a0 x ,a0 y ), (a1 x ,a1 y ) and (a2 x ,a2 y )? They are points! In other words, by using a parametric representation of our curve, we've found a way to represent our curve by referring to particular control points !

Unfortunately, using these points as control points is not very intuitive. If you play around with them, then you'll find that changing their values (even slightly) won't necessarily give you an easily understood change in the shape of the curve. But our parametric shenanigans do suggest that there may be some way we can 'tweak' things so that, using just three points, we can represent a second order curve in an intuitive fashion. See how we have represented a parametric curve as a sum of polynomials. Such a representation is often termed a polynomial basis function . The term 'polynomial' should be clear, but what do we mean by 'basis function'? If we look into things a bit further, then we find that we can more generally represent a point on a curve using equations like:

C(t) =     k

p i b i (t)
  i=0

This needs careful examination. Let's use the above to determine, say, the x coordinate that corresponds to a value t. What we are saying is that the x coordinate position C x (t) is the sum of the x positions of several points {p 0 .. p k }, with the value of each x position being weighted using a basis function , b i (t). When we said

C x (t ) = a0 x .t 2 + a1 x .t + a2 x

up above, we were using what is called a primitive polynomial basis function . Now look at the following curve, and its control points:

picture of Bezier curve with four control points

The four control points (there are four, so it's a cubic curve) are shown in black, the curve in red, and the 'bounding polygon' that links the control points, in green. Neat, isn't it? (Unless you're colour blind)! With this setup, the curve lies within the convex hull of the control points (so we know where it cannot go). The way something like this is achieved (the convex hull property), is to ensure that:

      k

b i (t) = 1
  i=0

What we are saying is that for any value of t, if we add up the result of the basis functions applied to t, we get one. So when we work out the various values for p i multiplied by b i (t), all we are doing is constructing a weighted average of the p i values. This in turn means that the resulting point must be "somewhere in between" all the points - that is, an "average" value. Note that this will be true, however many dimensions we are working in, because of the parametric nature of our equations - each parametric equation applies to just x, y, z or whatever! (We usually don't allow t to become less than zero or greater than one - we only look at a particular section of the curve - and we also ensure that basis functions don't become negative during this interval).

Cubic Bezier

As we mentioned, the cubic Bezier has only four control points, just like the curve we drew above - P0, P1, P2 and P3. Two of the control points we will call the origin and destination end-points - we'll represent them by (x0,y0) and (x3,y3) respectively. The other two control points are then (x1,y1) and (x2,y2). We will start off with a simplistic approach to drawing the Bezier curve (using a primitive polynomial basis function), and then, later on, we'll explore better ways of doing things!

A simplistic approach!

Let's draw the curve from (x0,y0) to (x3,y3). We will do this by varying our parameter t from zero to one as we move along from origin to destination. There will be a cubic equation that defines the value of x for any particular t, and another cubic equation that gives us the y position for that same value of t. We write the equations for these curves as:

x(t ) = a x t 3 + b x t 2 + c x t + x0

y(t ) = a y t 3 + b y t 2 + c y t + y0

Cunningly, the Bezier control points are set up so that:

It is possible from the above equations to work out the values of a x , b x and c x , given the four point coordinates, and likewise for a y , b y and c y . Here we go (but you may wish to work things out for yourself, first, as the calculations are very simple):

.. and likewise for a y , b y and c y . You can imagine an object moving from the origin towards the first control point, and then gradually coming under the influence of the second point before - pop - it crashes into the destination! It should be clear that if we choose say one hundred values of t between zero and one, with an equal interval of 0.01 between these values, there is no reason why the distance moved between successive points should be the same. On the contrary, because we're using cubic equations, we expect greater or smaller jumps in the x and y directions as we move progressively from origin to destination. This has some practical significance in drawing our Bezier curve, as we might find that, for a certain chosen interval, we waste time calculating too many points on one region of the curve, while in other regions, our points are too far apart!

A better approach - De Casteljau's algorithm

There's a better way of drawing Bezier curves. It's named after Paul de Casteljau, who thought up 'Bezier' curves a little before Bezier did, while working for Citroën (Bezier worked for the opposition - Rénault. Needless to say, both sides kept their ideas secret for years)!

Let's play with the curve we constructed above:

picture of Bezier curve with four control points

We'll do several things. We will choose a parameter t , and use this parameter to subdivide three edges of the bounding polygon, that from the origin P0 to P1, that from P1 to P2, and a final edge from P2 to P3. We can of course choose any value for t between zero and one. Let's say (just for demonstration purposes) that we choose a value of about a third. We proportionally divide the edges P0P1, P1P2, and P2P3 using t , and mark off the three new points indicated by this subdivision. We will call the three new points P0', P1' and P2':

subdivided Bezier curve

What happens if we connect up P0', P1' and P2', and then repeat the process of subdividing the two resulting line segments? We are now down to two new points, P0'' and P1'', which we can in turn connect with a single line segment.

further subdivided Bezier curve

Finally, we take this single remaining line segment and apply our parameter t to it, and we have a point. Let's accept for the time being that this final point is on the Bezier curve (it is)! Here we have it:

further subdivided Bezier curve

Look more carefully at the diagram above. On the left of the drawing we have the points P0, P0', P0'' and then finally the Bezier point on the curve, B(t). Working from the right we could identify P3, then P2', P1'', and finally B(t) again. It's almost as if we have now subdivided the Bezier curve into two Bezier curves, each with its own bounding polygon! In fact, we have. Let's accept this as an article of faith (for the time being)! In the following picture we've drawn the right subdivision of the Bezier curve, with its bounding polygon:

further subdivided Bezier curve

See how on the left , if you were to draw in a bounding polygon, it would already quite closely approximate the Bezier curve. You can soon appreciate that if we repeat the above process of subdividing the each of the new Bezier curves into two, (and so on), the bounding polygon will rapidly become almost indistinguishable from the curve itself. This is a really super "divide and conquer" algorithm for rapidly constructing a Bezier curve!

You should still be unconvinced, because we have asked you to trust us that:

  1. The point B(t) above actually lies on the curve; and
  2. The points P0, P0', P0'' and B(t) really do define the bounding polygon of the new, subdivided left curve, and likewise for P3, P2', P1'', and B(t) on the right.

Okay. Let's explore these assumptions! On the surface, the assumptions at least seem consistent, for if B(t) lies on the curve, then there is no good reason why P0' and P0'' shouldn't be control points, and likewise for P2' and P1''. As required, each of the two new "sub-curves" will have an origin, a destination, and two other control points, and so on down the line, as we continue to subdivide each curve in turn.

What is the x co-ordinate of P0'? It must be:

P0'x = t.P0 x + (1-t).P1 x

Likewise, we can work out that:

P1'x = t.P1 x + (1-t).P2 x
P2'x = t.P2 x + (1-t).P3 x
P0''x = t.P0'x + (1-t).P1'x
P1''x = t.P1'x + (1-t).P2'x
B x (t) = t.P0''x + (1-t).P1''x

We obtain similar equations for the y values. Let's eliminate all P' and P'' values, by substituting the various values from the above equations into:

B(t) = t.P0'' + (1-t).P1''

We obtain:

B(t) = t(t.P0' + (1-t).P1') + (1-t)(t.P1' + (1-t).P2') .. and so on, to get:

      = t 3 P0 + 3t 2 (1 - t).P1 + 3t(1 - t)2 .P2 + (1 - t)3 .P3

Now, if you care to, you can examine our initial simplistic cubic equations above:

x(t ) = a x t 3 + b x t 2 + c x t + x0

y(t ) = a y t 3 + b y t 2 + c y t + y0

.. and indeed verify that our new Bezier equation is consistent with the way the control points were 'set up' for the primitive polynomial basis functions. You can now see that we don't have to prove our two assumptions - that B(t) lies on the curve, and that we can use the above technique to subdivide the curve into two new Bezier curves. We actually define a Bezier point in terms of our construction, and then apply this construction recursively to create our whole curve. The above equation for B(t) is a consequence of our construction.

Note that we still have to prove the convex hull property for our curve, that is, show that:

      k

b i (t) = 1
  i=0

Now, the sum of the basis functions is: t 3 + 3t 2 (1 - t) + 3t(1 - t)2 + (1 - t)3

You won't be surprised to find that this works out to 1, so the convex hull property is satisfied. You might also wish to play around with the equation for B(t) a bit more, and show that:

Limitations of Bezier curves

Bezier curves have several limitations. In particular, some simple curves (such as ellipses) cannot be accurately represented by them. In addition, each control point in a Bezier curve will, to a certain degree, affect the whole curve. The latter property is called non-localness . A more general type of curve is the Basis spline (B-spline), basically (heh) thought up by Lobachevsky in the late 1700s, and further developed by de Boor, Cox and Mansfield in the 1970s. This too, however, still cannot represent a simple shape like an ellipse, although it doesn't have the problem of non-localness. The much more powerful Non-uniform rational B-spline (NURBS) conquer the problem of representing geometric shapes like ellipses and circles, and do much else besides. (There is also something called the rational Bezier which can be used to draw ellipses, etc., but is less powerful than the NURBS).


Font metrics

Metrics refer to the relationship between glyphs as they appear on the page (or screen) - in other words, glyph placement. This is complex. Metrics are usually specified in notional units that are relative (to glyph properties, not screen dimensions). Each scalable font has global properties - things such as the:

Layout of glyphs may be conventional (right to left, otherwise called roman ), vertical, or left to right.

Let's look at some common terms:

  1. The baseline is an imaginary (virtual) line that is used to 'line up' glyphs. It needn't run horizontally - for example, Chinese characters are aligned vertically, in which case glyps are centred around the baseline (or, if you wish, the baseline runs through the middles of the glyphs)!

  2. The pen position is a virtual point on the baseline from which things "kick off" when drawing a character. The actual character is drawn by moving the pen position. When the next character is drawn, the pen is lifted and moved to the next pen position. We call the distance between two successive pen positions the advance width (also discussed below).

  3. The terms ascent , descent and linegap are only used with horizontal layouts. The ascent is measured from the baseline up to the highest point drawn on the glyph outline; the descent measures the distance down from baseline to lowest point. The linegap is that additional distance separating two lines of text. By convention, the ascent is positive, the descent is negative and the linegap is positive, so to calculate the desired distance between two successive baselines, one must work out:

    linegap + ascent - descent

    Note that in some fonts, multiple differing copies of ascent, descent and linegap values are provided (thanks, Windows)! Another name for the line gap is the external leading . ("Leading" is an old printing term - leads and slugs were used to separate lines).

  4. The bounding box (bbox) is a virtual box into which the glyph just fits. Four values are provided (!), representing maximum and minimum values in the x and y directions, that is xMax, xMin, yMax and yMin.

  5. The internal leading is the space you have above a character to fit in accents, etc. {Assuming the character itself lies in the EM square}, the internal leading can be calculated as:

    ascent - descent - EM size. {???}

  6. bearings and advances - there are several of these (for now, we will only consider horizontal layouts):

Stretching

A smart program that places glyphs on your screen or paper may play around with the left side bearing and advance width. Scaling of metrics and grid-fitting of glyphs can be slow , so some truetype fonts may contain additional information about pre-computed metrics for commonly-used sizes.

Hinting

Hinting is used in type 1 fonts to "pretty up" representation of glyphs when they are displayed at a low-ish resolution. Hinting indicates which features are 'important', so that if a font pixel falls on the boundary between two display pixels, a decision can be made as to how the pixel should be shown. Another (perhaps better) solution has been used for truetype fonts, and is discussed when we consider them in detail. Hinting points out things such as stems, important widths (for example, the verticals of the letters I and T should be of similar width), and a few other characteristics. Some glyph formats leave it up to the renderer to decide what features to emphasize ("automatic grid fitting"), which can result in very variable results.

Kerning

Kerning is simply placing two characters closer together. For example, if we wanted to print the word ADVANCE, it would make sense to move the V and the A closer together, rather than having a big space between them. The 'left foot' of the A could even be moved below the rightmost part of the V, so the bounding boxes of the two characters effectively overlapped.

Ligatures

Consider a word like "fluffing". See how clumsy it looks when we write it in a monospaced (fixed width) font:

fluffing, compared with our more usual variable width font, thus: fluffing. Note particularly how the "fl" and the "ffi" are printed closer together - printing the characters separate is so ugly that special 'combination' characters (ligatures ) are used to render these combinations - in any decent rendering of "fi", the dot of the "i" should be left out. You could see this as an extreme case of kerning, where the characters get so close together that one or both is modified in the interests of beauty! The two common ligatures are "fl" and "fi", although in some font faces, "ffi" too has its own ligature.

Font smoothing

This is even more sexy - if you have a point that is part of a glyph, and despite your best efforts, the point sits on the boundary between two pixels, the glyph will often look better if both of the bounding pixels are rendered as grey, rather than one being arbitrarily chosen as black and the other as white. Such rendering is commonly performed by making a larger bitmap and then applying a filter. Note that this smoothing is best applied to diagonals and curves - overuse on horizontals and verticals makes characters look really blurry and unattractive.

Device Independence

Rendering of text should always be device-independent. How many times have you written a document in MS Word, carefully adjusted everything so it looks pretty, and then printed the document on another printer only to have the whole thing screwed up? You often end up with lines on new pages, and so on. This is because MS Word doesn't preserve device independence, rather placing text according to the particular properties of the current printer!


Font families

If we're going to talk about families of fonts, it's probably best to first distinguish between ugly fixed width fonts, and the ones we're more used to - variable width fonts. Fixed width fonts (like OCR-B, and the ubiquitous and nasty Courier) have only one merit - the vertical columns of letters line up. This is really rather important when you're reading computer text that's based on columns (for example, program listings, or samples of computer code). But most 'user-friendly' text has glyphs of different widths - the letter "m" in most font families is wider than an "n", which itself is usually far wider than the "i".

We've already talked about serifs, and the presence or absence of serifs gives us another convenient way of making broad distinction between fonts - are they serif (such as Times Roman) or sans serif (like Lucida, Verdana, MS Comic, Myriad, Arial, and so on)?

Serif Fonts

Fonts go back a long way. Things really kicked off in about the 15th century, with complex, curly, and very difficult to read "blackletter" fonts, Old English and the like.

Smart, aesthetically savvy font designers then hybridized the old 'carolingian' scripts and new printing technology, creating rather attractive Antiqua fonts. (Unfortunately, and rather confusingly, this term has subsequently been used for all sorts, so many people now refer to these as 'humanist Antiqua', or Old Style ).

Old Style is characterised by "low contrast" - strokes and serifs have fairly constant widths, by complex rather non-linear strokes, and serifs that curve where they join the strokes. Strokes are often made thicker at the bottom left and/or top right of the glyph, something like normal neat handwriting! Italic faces of Old Style gradually became more 'slanty' as Old Style evolved. Examples of Old Style fonts are Garamond , Jenson, and Goudy Old Style. Some divide old style into 'Venetian' (Berkeley Oldstyle, Clearface), and 'Garalde' (Garamond). We should also probably mention Palatino, somewhere.

In contrast to Old Style, we have Modern fonts. These are fonts with attitude - they are lighter, and have emphasis on the (heavy) vertical strokes. Serifs are thin. The high contrast of modern fonts may make them less readable. Examples are Bodoni , New Century Schoolbook, Fenice, and of course many fonts with the word 'modern' in their names - Computer modern, and so on. Modern fonts are sometimes called didone fonts.

"In between" Old Style and Modern are so-called transitional fonts, such as Times Roman , Utopia, Bulmer and Baskerville, and possibly Caslon (which some regard as old style). As their name suggests, these tend to combine the readability of Old Style fonts and the character of moderns. Some even regard "Times" as old style!

Somewhere out on the edge are fonts with thick chunky serifs - the slab serifs , such as Nile, Egyptienne, Clarendon and Memphis (note the prevalence of Egyptian-related names, said to be related to their evolution after Napoleon returned from Egypt)! They are often surprisingly readable, and photocopy well!

Sans Serif

Sans serif fonts are a remarkably modern invention, and can be sub-classified into:

Decorative Fonts

A note on decorative fonts - avoid them - they're largely illegible! (Including e.g. uncial fonts, and handwriting-like script fonts ).


PostScript

Adobe created the language PostScript for Apple in about 1985. The most important things about PostScript are that it is:

The printer you are talking to with PostScript understands that it has a page of a particular size that you are going to draw on. The lower left corner of the page is (0,0) - the coordinates are standard Cartesian ones, with the positive x axis to the right, and the positive y axis going upwards. As we might expect, measurements are by default in points (1/72 in). Although raster graphics can be printed on PostScript printers, the really sexy part is use of vector graphics - our friendly cubic Beziers! The printer 'page' is represented by a buffer in the printer memory.

Note that it is now possible to simulate a PostScript printer using smart software. See GhostScript. This tends to be rather slow, and may not wholly adhere to the Adobe standard. (Apple software that does a similar job includes "Freedom of Press" and "T-Script").

PostScript is always interpreted, not compiled. Notation is the same reverse Polish notation (RPN) used in Hewlett-Packard calculators. As you might expect from the RPN format, stacks are used rather intensively. The nice thing about RPN (remember that on an HP calculator, "3 * 4" would be rendered as "3 enter 4 enter *") is that it is unambiguous, without any parentheses. "3 enter 4 enter *" means "push 3 onto the stack, then push 4, and then take two things off the stack, multiply them together, and push the result back onto the stack". You cannot have the confusion engendered by standard 'infix' notation with statements like "3 + 4 * 5", which confusion is only resolved when we decide that "*" takes precedence over "+". In RPN it's either "5 4 * 3 +" or "5 4 3 + *".

Postscript has two main stacks, an operand stack , where arguments such as 3, 4 and 5 are pushed before they are used (as in our RPN example), and a dictionary stack that provides a storage area for dictionaries. In PostScript, we refer to 'arguments' by the more generic name of operators .

What is a dictionary? PostScript allows you to use dictionaries to look up the values of things. There are two main dictionaries:

  1. sysdict
  2. userdict
The sysdict can only be read, but you can make up variables on the fly and store their values in the userdict, retrieving them later. Note that you can create, name and store a dictionary of your choice within another dictionary!

You can store data in PostScript arrays. Practically anything can be slotted into these arrays (they are 'weakly typed'). You can even shove a procedure into an array structure, and then run the procedure! (An executable array is called a procedure body ). A procedure is 'invoked' by mentioning its name, or by using the exec operator on a procedure body stored on a stack. The basic idea behind procedures is that you can take a whole sequence of instructions, give it a name, and then execute the instructions sequentially by mentioning that name.

How do we create a name? First of all, choose a name. Try and avoid using anything other than the letters a..z, A..Z, and the numbers 0..9. Do NOT start a name with a number (although it is sometimes permissible) as someday such practices will bite you. Peculiar names that are legal in PostScript include '[', ']', '=', '==', '<<', and '>>'. Note that these names are written without the 'quote marks' - we just surrounded them with quotes because we're silly!

To put a name on the stack , precede the name by a /slash.

Numbers in PostScript may be integers or reals. Generally, you should use the standard Scientific mantissa E exponent format for numbers, although radix #value is another permissible format.

Strings are simply placed in brackets thus: (This is a string). An alternative is to place the hex codes for the characters in angle brackets thus: <20414220> is the same as ( AB ). <--{Look up escape codes}!-->

Let's take a closer look at PostScript syntax. Here are some examples:

A really good first introduction to PostScript is at indiana.edu.

Portability

Okay, it is just possible to screw things up by writing scripts in PostScript that assume things like the resolution of a printer, or the number of paper trays it has. Avoid this sort of intensely stupid practice!

GhostScript

GhostScript is a PostScript interpreter. You can generally print any PostScript file, even without a fancy PostScript printer. Ghostscript can also interconvert PostScript and PDF (Portable Document Files), with some limitations. The C source code for its graphic capabilities is available! AFPL ('Aladdin') GhostScript is a non-commercial freeware version, and there is also a GNU version (under the Gnu public licence), and a commercially licenced version from Artifex. GhostView allows you to preview PostScript files.


Practical Fonts

Computer fonts really got going with Adobe. Adobe held the market with the Type1 font standard - (that's type one, not type ell) - until Apple and Micro$oft collaborated to define the TrueType font. You can recognise the various ways of defining fonts not only by the company the files keep, but also the file suffixes:

You might think from the above that there were three types of fonts, but in fact the .afm files define only the font metrics , while the glyph shapes are contained in the .pfa or .pfb files. You will also sometimes come across the term Type42 font, which is just a truetype font with special headers so that it can be used by a "postscript" interpreter. The Type3 font is seldom used, but similar to type1.

You will find that grown up applications such as GhostScript support both type one and truetype fonts. TrueType fonts use quadratic Beziers, while Type 1 are cubic. Occasionally, you will come across the rather sexy Metafont of Donald Knuth, with a .mf extension. Sexy, but slow and not commonly used, except in the TeX typesetting system, which just happens to be used in LaTeX, the premier system for creating scientific documents!


Type 1 Fonts

The definition of Type 1 fonts depends heavily on a knowledge of PostScript. A vast amount of detail is contained in various Adobe publications, the "red book" and so on. Of most interest however is the "black book", which contains the encoding format of Type 1 fonts. Formerly a closely-guarded secret, the black book is now freely available on the web. This is only because Adobe suddenly realised that Microsoft/Apple TrueType fonts were taking over, and releasing the black book was their only defence! Score one for competition between software writers!


TrueType (TT) Fonts

Let's get down to the nitty gritty. It's convenient to identify four classes of data in TT -

  1. face data - data independent of scaling, transformations, and particular glyphs, for example font family, style, Panose number, typographic ascenders and descenders (as well as a whole lot of other fancy stuff);
  2. instance data - some very specific tables that talk about specific resolutions, etc.
  3. glyph data - descriptions of specific glyphs (outline, and metrics such as bounding box, bearings, and advance values, as well as a very special glyph code that is used to improve rendering of tiny characters).
  4. text & layout data - how to group glyphs (font metric information) including a kerning table, ligatures, baseline management, justification, and so on.

TT data points are stored in a format that indicates:

  1. coordinates of the point
  2. a flag that is "on" or "off"

Rules for constructing a contour out of TT data points are:

  1. two "on" points must be connected by a line segment;
  2. one "off" point between two "on" points indicates a conic Bézier, (the off point is the control point of the Bézier);
  3. two "off" points force the rasterizer to do something very strange - to create another "on" point exactly half-way between the "off" points. You can see that the result is to create a couple of Bézier arcs!

You can see that the terms "on" and "off" are very satisfactory, because "on" points are indeed on the curve, and "off" points are Bézier control points that are indeed never coincident with the curve!

Drawing small glyphs in TT

TT uses an approach different from the "hinting" of type 1. Each glyph has an associated set of "bytecodes", which specify a "program" in a geometric language! This tiny bytecode program is a brilliant solution to the problem of drawing small glyphs, as it allows optimal alignment of each outline point to the pixel grid, preserving metrics and providing excellent results! The associated problem (isn't there always one?) is that a rubbishy bytecode program will generate a hideous glyph. Needless to say, the bytecode language is low-level, tricky, and has over 200 operation codes. The designers of the bytecode cling desperately to it, making it nigh-impossible for ordinary people like you and me to get reasonable-priced access to tools that would allow us to design attractive fonts! Oh, another thing - if you use certain of the Apple bytecodes in rendering your fonts, you have to pay them a royalty.


LaTeX

LaTeX (yes, the name is not pretty) is a smart way of using the TeX typesetting system mentioned above. Although born and bred for Unix, versions of Latex are also available for Windoze. Latex is designed with the idea that the fancy print shouldn't get in the way of information content, and is the way to go if you have a big, complex scientific document (or set of documents) with lots of cross-references and the like.


References

  1. http://www.webreference.com/dlab/9802/ - Great!

  2. http://www.oucs.ox.ac.uk/ats/fonts.html

  3. http://www.linuxdoc.org/HOWTO/Font-HOWTO.html

  4. http://www.monotype.com/newmedia/type101_ex.htm

  5. http://www.richinstyle.com/guides/fontface2.html (CSS2 tutorial)

  6. http://freetype.sourceforge.net/freetype2/docs/glyphs/index.html (Superb stuff on glyphs) Homepage is http://freetype.sourceforge.net/freetype2/

  7. http://www.w3.org/TR/2000/CR-SVG-20000802/index.html (Scalable Vector graphics specification from W3C)

  8. http://www.ib.hu-berlin.de/~mh/css/css2/fonts.html (CSS2 fonts)

  9. http://www.hypermedic.com/style/fonts/fontglos.htm (Font Glossary) The elderly FAQ is at http://nwalsh.com/comp.fonts/FAQ/ OR http://www.faqs.org/faqs/by-newsgroup/comp/comp.fonts.html

  10. http://www.cs.ruu.nl/wais/html/na-dir/internationalization/font-faq.html (Free Fonts)

  11. By the way, a good (Google) search for EM squares is: "glyph font EM square 1000 2048"

  12. http://partners.adobe.com/asn/developer/pdfs/tn/T1Format.pdf Online version of Adobe type 1 "black book"

  13. http://cgm.cs.mcgill.ca/~luc/ttsoftware.html (Pointers to software, good, includes pointer to Adobe black book)

  14. http://www.wotsit.org/search.asp?s=font (Wotsit's formats)

  15. See http://www.paratype.com/default.asp?page=/library/class/class.html?class=serif for sample fonts (several).

  16. http://www.cee.hw.ac.uk/~ian/hyper00/curvesurf/morebez.html (Good stuff on Bezier curves)

  17. http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/notes.html

  18. http://www.cs.indiana.edu/docproject/programming/postscript/postscript.html (A First Guide to PostScript)

  19. http://www.adobe.com/products/postscript/resources.html#white (Adobe technical papers)

  20. http://www.inkguides.com/postscript.asp (Excellent PostScript/GhostScript general reference)

  21. http://www.cs.wisc.edu/~ghost/index.htm (GhostScript Home page). See also the faq.

  22. http://www.mactech.com/articles/mactech/Vol.09/09.04/PostscriptTutorial/ (Apple Mac orientated description of PostScript).