Main index Placemat: main guide About author

Valid HTML 4.01 Transitional

The glasses placemat: PostScript code within parameters

Julian D. A. Wiseman

Contents: Code inside compound strings: summary; Code inside compound strings: examples; Variables that parameters may inspect.

Various of the parameters of the placemat are intended to hold code, or can accept code as well as simpler types. Herein find explanation and examples.

It is assumed that the reader is familiar with the simpler parameters of the code to make the glasses placemat, described at

Code inside compound strings: summary

In the compound ‘strings’ of arrays ([]), it is permitted to include PostScript code as well as strings (()) and glyphs. It is intended that such code do only the following:

When user code within compound strings is being executed the current dictionary is UserScratchDict, which persists between executions of such user code. UserScratchDict will therefore hold any variables deffed. To avoid name clashes users should not store anything.

Code may assume that there is a currentpoint and currentfont, and this should still be true after execution. Any changes made by the code to the current path should be made by rmoveto, rlineto, and rcurveto; code should not alter the dictionary stack; nor alter anything that was on the stack at the start of code execution; nor leave changed the currentmatrix; nor change any of the many code variables.

User-entered code has the same access permissions as the program. Hence wilful or careless code can cause arbitrary confusion. Use with care, or not at all.

Code inside compound strings: examples


Smith Woodhouse, unkerned
Smith Woodhouse, kerned

Some pairs of letters look better if nudged closer together. This is particularly true either side of a “W”, “V”, and even more if either of the neighbouring characters is an “A”. Compare the two versions of “Smith Woodhouse” (shown magnified 3×): the first not kerned; but in the second the “W” and “o” have been brought closer together with code thus:

	[(Smith W) {-0.09 Kern} (oodhouse)]

The code in the parameter acts as if laying out the characters in an ordinary straight line. But when this is rendered as a part of one of the Circlearrays, the program keeps track of changes to the currentpoint, and converts horizontal changes to angular ones.

JDAW, unkerned
JDAW, kerned

The author’s own initials, “JDAW”, also benefit from kerning, the two variations of these names being generated by:

/Names [ 
	[(JDA) {-0.08 Kern} (W)] 
] def

(The amount of the kerning is controlled by the “-0.08”: the optimal amount differs for different pairs of letters and and different typefaces.)

As these placemats are used by the author for port tastings, the same names keep recurring. Hence it makes sense to define well-kerned versions of these, most easily done by putting before the parameters the following definitions.

/JDAW [ (JDA) {-0.13 Kern} (W)] def
/Grahams [(Graham) {-0.04 Kern} /quoteright {-0.04 Kern} (s)] def
/OffleyBoaVista [(Of) /fl (ey Boa Vista)] def
/RebelloValente [(Robertson) {-0.04 Kern} /quoteright {-0.09 Kern} (s Rebello V) {-0.092 Kern} (alente)] def
/SmithWoodhouse [(Smith W) {-0.075 Kern} (oodhouse)] def
/Taylor [(T) {-0.092 Kern} (aylor)] def
/Vargellas [(V) {-0.092 Kern} (argellas)] def
/Vesuvio [(V) {-0.10 Kern} (esuvio)] def
/Warre [(W) {-0.065 Kern} (arre)] def

Water and alcohol

H2O rendered neatly
CH3CH2OH rendered neatly

A vertical shift of the current point can also be useful, for example to to render the likes of “H2O” or “CH3CH2OH”. These are most elegantly done with repositioned /twosuperior and /threesuperior glyphs (“²”, “³”):

	{0 CurrentFontSize -0.5 mul rmoveto} /twosuperior 
	{0 CurrentFontSize  0.5 mul rmoveto} (O)]
	{0 CurrentFontSize -0.5 mul rmoveto} /threesuperior
	{0 CurrentFontSize  0.5 mul rmoveto} (CH) 
	{0 CurrentFontSize -0.5 mul rmoveto} /twosuperior
	{0 CurrentFontSize  0.5 mul rmoveto} (OH)]

Superscripts and subscripts

Superscript th rendered neatly

However sometimes a superscript is needed, in the sense of an ordinary character shown small and raised. For simplicity there are pre-written commands {SuperscriptOn} and {SuperscriptOff}. These are typically used in the header, as in the example in the right (though can of course be used in the Circlearrays).

/HeaderLeftText [ (Saturday 9) {SuperscriptOn} (th) {SuperscriptOff} ( February 2008, Boston) ] def
H2O rendered using SubscriptOn
CH3CH2OH rendered using SubscriptOn

Likewise {SubscriptOn} and {SubscriptOff} can be used to render “H2O” and “CH3CH2OH”, as in the two following items of Circlearrays.

[ [(H) {SubscriptOn} (2) {SubscriptOff} (O)] ]
[ [(CH) {SubscriptOn} (3) {SubscriptOff} (CH) {SubscriptOn} (2) {SubscriptOff} (OH)] ]

Typeface changing

Changing typeface mid-string

Changing the typeface mid-string is permitted, as in this hypothetical item of Circlearrays:

	[{/TimesNewRomanPSMT CurrentFontSize selectfont} (Times)] 
	[{/Helvetica CurrentFontSize selectfont} (Helvetica)] 


Fiddly dot under s

Berry Brothers’ name contains an abbreviation, shown as a small “s” above a dot. The code below starts by saving the current font size in BrosOriginalFontSize. Then it calculates the height of the “s” (using the handy StringHeight function), of the “o”, and the dot, from which it can deduce the font size such that the dot, a gap half height of the dot, and the “s”, in the new size, sum to the height of the “o” in the old, and also deduce the vertical offset of the “s” (BrosVerticalOffset). Then the code changes the font size, and rmovetos up (it would also rmoveto right if the dot were wider than the “s”). Shows the “s”. Moves back down, and horizontally such that the s and the dot will have aligned centres, and shows the dot. Moves forwards to the end of the “s” (since the dot is narrower), and finally reverts the font size back to BrosOriginalFontSize, before showing the remainder of string (“ & Rudd Selection”).

	(Berry Bro) 
		/BrosOriginalFontSize CurrentFontSize def
		/BrosHeight-s (s) StringHeight def
		/BrosHeight-dot (.) StringHeight def
		/BrosHeight-o (o) StringHeight def
		/BrosVerticalOffset  BrosHeight-o  BrosHeight-s 1.5 div BrosHeight-dot div 1 add  div  def
		BrosOriginalFontSize BrosHeight-o mul  BrosHeight-dot 1.5 mul BrosHeight-s add  div   
		/BrosWidth-s (s) StringWidthRecursive def
		/BrosWidth-dot (.) StringWidthRecursive def
		BrosWidth-dot BrosWidth-s gt {BrosWidth-dot BrosWidth-s sub 2 div} {0} ifelse  BrosVerticalOffset  rmoveto
	{BrosWidth-s BrosWidth-dot add -2 div   BrosVerticalOffset neg   rmoveto}
		BrosWidth-s BrosWidth-dot gt {BrosWidth-s BrosWidth-dot sub 2 div 0 rmoveto} if
		CurrentFontName BrosOriginalFontSize selectfont
	( & Rudd Selection)

Dingbat drawing code

Including code that makes a glyph

It is permitted to include code that renders a shape. The following (in the example on the right used in Titles, Subtitles, Circlearrays and FillTexts) calls a routine, Star, that takes parameters:

leaving on the stack a dictionary containing useful values (LeftX CenterX RightX BottomY CenterY TopY Radius InnerRadius AntiClockwise).

		/Left /Bottom BaseHeight /Height 90 7 3 false false Star  fill  begin RightX BottomY moveto end
		/EffectiveNumCharacters 1 def

(The /EffectiveNumCharacters 1 def tells the code how many characters is this shape, and is used by SameSizeTitlesIfAllOf. Of course the shape rendering code must finish by leaving the currentpoint at a suitable place.)

Users with competence in PostScript, or willing to acquire a little of same, will find it possible to do much or all of the text formatting that might be wanted.

Different people, different parameters

Normally the glass descriptions will be the same for each person’s setting. But Titles, Abovetitles, Belowtitles, Overtitles, and FillTexts may be code that refers to NameNum. Particularly if FillTexts are used, this can substantially increase distill time, file size, and perhaps print time. By default the program assumes that these parameters are constant over users: they are rendered once (using execform), thus reducing file size and distill time. If parameters do vary with NameNum, it is important to /VariesByNameTitlesAboveBelowOverOrnaments true def. (But don’t do so idly, as it greatly increases the file size.)

Variables that parameters may inspect

Many parameters may be set to code, and this code may access internal variables. E.g., /OutlineTitles {WithinPage 2 mod 0 eq} def will make alternate circles outlined and not.

Several variables may well be available.

The page entitled PostScript Routines lists some of the functions defined in the code, and these may be used by parameters. Noteworthy are BaseHeight, StringHeight, StringWidthRecursive, ShowRecursive, and CharPathRecursive. Also available will be any of the parameters to the code, as described on this page or on the main guide.

0 1 MakePathConnectingGlasses 1 0 MakePathConnectingGlasses

The code PaintBackgroundCode may draw directly on the page, and does so before anything else is drawn. Its brother, PaintForegroundCode, is executed after the other elements of the page have been painted. Either can be used to add a corporate logo. It is expected that either piece of code, if non-empty, would inspect TypeOfPagesBeingRendered and perhaps SheetNum. If it is wanted to paint inside the Glasses circles on all the pages on which they are repeated, instead use PaintBackgroundInsideGlassCircles, as necessary accessing SheetNum, WithinPage, and WithinTitles. When this is called the centre of the circle is at 0,0; and the paintable area is clipped to radius Radii SheetNum get.

Available for use by PaintBackgroundCode and PaintForegroundCode is MakePathConnectingGlasses, a routine taking two integers, and making a path between points Radii SheetNum get away from those glass positions. The integers must be ≥0 but < the length of GlassesOnSheets SheetNum get. If the two items have similar x or y, the path drawn will be vertical or horizontal. Otherwise the line will emerge from the first position horizontally, and enter the second vertically.

Hence the following example of PaintBackgroundCode, on two otherwise identical seven-glass five-row portrait pages, will add lines as on the example above-right.

	TypeOfPagesBeingRendered /Glasses eq
		0 1   SheetNum 1 eq {exch} if   MakePathConnectingGlasses
		0 2   SheetNum 1 eq {exch} if   MakePathConnectingGlasses
		1 2   SheetNum 1 eq {exch} if   MakePathConnectingGlasses
		6 setlinewidth  0.5 setgray  0 setlinecap  stroke
	} if  % TypeOfPagesBeingRendered /Glasses eq
} def  % /PaintBackgroundCode

There is also PrologueCode, executed only once, after calculating radii and font sizes and the like, but just before painting pages; and its brother EpilogueCode, executed just after painting pages. The page size will be set after executing these, so though these can be used to create extra pages (the user-supplied code calling SetPaperSize or setpagedevice and then showpage), they are not an equivalent to PaintBackgroundCode or PaintForegroundCode.

Julian D. A. Wiseman

Main index Top About author