[comp.lang.postscript] SmallCapsFont

tinkelman@ccavax.camb.com (Bob Tinkelman) (07/19/89)

I have written a procedure to build a Small-Caps versions (a la LaTeX) of
fonts.  My code is attached.  I've also forwarded a copy to Mario Wolczko 
<mario@ux.cs.man.ac.uk>, the author of the PS-LaTeX package that we have
been using here at Cambridge Computer Associates.

My reason for posting it here is to get some feedback from others with more
experience dealing with PostScript fonts.  Other than the usual types of
comments on programming style, efficiency, etc., I'd welcome feedback on
a couple of specific questions:

1. I decided not to cache the font.  My reasoning was that as the underlying 
   fonts *would* be cached, the major work of rendering-the-dots wouldn't need
   to be redone each character.  I assumed that the additional savings of
   avoiding my BuildChar routine would be minor in comparison.  (Is that true?)
   In addition, I thought that I'd be wasting font cache memory which could be
   better used for "other characters".  That obviously depends on what else is
   going on in the document and the size of the font cache.  (What are your
   thoughts on the tradeoffs?)

2. I implemented a linear scaling of 0.8, uniformly in both X and Y.  I didn't
   give this a lot of thought.  I did it because Mario Wolczko had provided,
   as part of PS-LaTeX, TFM (TeX Font Metric) files for various SmallCaps 
   fonts constructed this way.  The Blue Book gives an example of constructing
   Small Caps using a more adaptive scheme: 0.8 x-scaling and y-scaling
   computed to give letters with tops one third of the way between x-height 
   and cap-height.  Which is better?  

3. If I had decided to go with the Blue Book scaling method, I would have had
   to construct new TFM files.  I've seen programs for creating AFM files from
   "what's in the printer" which, although designed for the "built-in" fonts,
   I believe I could adapt to work for me.  I've also seen methods for building
   TFMs from AFMs, though I'd have to get one that worked under VMS.  The part
   that seemed to me to require manual work was kerning.  Is there any clean
   way to generate kerning info for pairs like "Th" where the "h" is now a
   short "H" which might reasonably be kerned a little under the "T"?

.-----------------------------------------------------------------------------.
| Bob Tinkelman                       | Internet: bob@ccavax.camb.com         |
| Cambridge Computer Associates, Inc. | UUCP: ...!{uunet,adelie}!ccavax!bob   |
| 56 Beaver Street, 3rd floor         | BITnet:   bob%ccavax@uunet.uu.net     |
| New York, NY  10004                 | AT&T:     212-425-5830                |
`-----------------------------------------------------------------------------'

--.--.--.--.--.--.--.--.--.--.--.--CUT HERE--.--.--.--.--.--.--.--.--.--.--.--.
% SmallCapsFont - construct a "Small Caps" font for use by PS-Latex

%Creator: Bob Tinkelman <bob@ccavax.camb.com>
%	  Cambridge Computer Associates, Inc.
%	  56 Beaver Street, 3rd floor
%	  New York, NY  10004  - USA

% This procedure is invoked with stack containing:
%	 /New-Font /Base-Font
% It clears the stack and defines the new font /New-Font in terms
% of the base font, /Base-Font

% Example of use:
%	/Times-SmallCaps /Times-Roman SmallCapsFont

% The new font produces the same results as the base font except for "lower
% case" letters (a-to-z).  For these, it outputs upper case (from the base
% font) scaled by .8 in each dimension.  [This method of scaling was chosen,
% in preference to the method recommended in the Blue Book (p157) only due
% to the availability of corresponding TFM files in the PS-Latex distribution.]

/SmallCapsFont          	% Stack: /New-Font,/Base-Font
{ 11 dict dup 			% Stack: /New-Font,/Base-Font,dict,dict
  3 1 roll			% Stack: /New-Font,dict,/Base-Font,dict
  begin				% Make the new font be the current dictionary
				% Stack: /New-Font,dict,/Base-Font
    findfont dup		% Find base font (leave /New-Font,dict on stack)
    1000 scalefont		%   Scale it by 1000
    /BaseFont-L exch def	%     and save as /BaseFont-L 
    800 scalefont		%   Also scale it by 800 and 
    /BaseFont-S exch def	%     and save as /BaseFont-S 
                                
    /FontType 3 def				% 3 means "User defined"
    /FontMatrix [.001 0 0 .001 0 0] def		% Scale by 1000 (see above)
    /FontBBox BaseFont-L /FontBBox get def	% Copy bounding box
    /Encoding BaseFont-L /Encoding get def	% Copy encoding 
  
    /TmpString 1 string def			% Storage for 1-char string
    
    /IsLowerCase				% See if char is a-z
     {dup  (a) 0 get ge 
      exch (z) 0 get le and
     } def
  
    /ToUpperCase				% Convert lower to upper case
     {dup IsLowerCase 
      {(a) 0 get sub (A) 0 get add} if
     } def
  
    /BuildChar					% Stack: font, char
     {exch begin				% font begin
        BaseFont-L setfont			% Set to large basefont
        dup IsLowerCase				% If char is a-z, then
          {BaseFont-S setfont ToUpperCase}	%   reset font & convert to A-Z
          if					%
        TmpString 0 3 -1 roll put		% put char into a temp string
        TmpString stringwidth			% get width of current char
        setcharwidth				% pass it to the font machinery
        0 0 moveto				% BuildChar builds chars at 0,0
        TmpString show				% output the temp string
      end %font%				% font end
     } def
  
  end %font dictionary

  definefont pop		% Define the font

} def % SmallCapsFont