2  INTRODUCTION  CHtoPX §1

1. Introduction. The utility program converts TEX raster pixel (“ ”) files into character pixel (“ ”) files. The file input by this program can be edited with a normal text editor, and the result can

be converted back to  format. The companion program  will convert a  file into a  file.
The first  program was designed by Lynn Ruggles in the spring of 1983. The programs  and

had a significant effect on the evolution of the present code.

A file may contain raster information for as many as 128 characters and as few as 0 characters. An exception to these rules is planned for oriental fonts; such fonts, however, are not allowed by this version of .

The banner string defined here should be changed whenever gets modified. define banner ≡ ´ ␣ ␣ ␣ ␣ ´ { printed when the program starts }

2. This program is written entirely in standard PASCAL, except that it occasionally has lower case letters in strings that are output. Such letters can be converted to upper case if necessary. The input is read from chr file, and the output is written on pxl file; error messages and other remarks are written on the error file, which the user may choose to assign to the terminal if the system permits it.

Each character ends with an page marker , which is set to chr(12) (cntl-L). This character can be changed for systems which do not use cntl-L’s in file formats. Whatever character is chosen should be one that will not appear at the beginning of a line. This restriction excludes all of the letters, and the symbols +, -, :, and blank.

The term print is used instead of write when this program writes on the error file, so that all such output can be easily deflected.

define print (#) ≡ write(error file, #) define print ln(#) ≡ write ln(error file, #)

program CHtoPX (chr file, pxl file, error file); const ⟨ Constants 21 ⟩ type ⟨ Types 5 ⟩ var ⟨ Global Variables 6 ⟩ procedure initialize;

begin ⟨ Open input and output files 11 ⟩ print ln(banner ); end of chr ← chr (12); end;

3. Here are some macros for common programming idioms.

§4  CHtoPX  FONT METRIC DATA 3

define incr (#) ≡ # ← # + 1 { increase a variable by unity } define decr (#) ≡ # ← # − 1 { decrease a variable by unity } define do nothing ≡ { empty statement } define shift (#) ≡ # ← # ∗ 2 { multiply by 2 } define shift and add (#) ≡ # ← # ∗ 2 + 1 { multiply by 2 and add one } 4. Font metric data. The file is in a format which allows it to be edited with a text editor. Once it has been edited, it needs to be converted back into a file which contains information that the TEX typesetting routines can use. These files store the information needed by TEX in a more compact way.

The character raster in the file sits in an almost invisible bounding box. This box is almost invisible in that all of the positions in the box are represented by blank spaces, except for the position of the x offset , the y offset , and the origin. These three positions are represented respectively by a dash (-), a bar (?), and a plus sign (+). The character raster sits at the lower right corner of the bounding box, which means that there may be space above or to the left of the raster, but not to the right or below it. None of the dimensions in the following information include the bounding box, but instead refer only to the inside box containing the character raster.

In the following information, the symbol (*) indicates that the information is used by the file, a (+) indicates that it is information about the total dimensions of the character raster, and a (-) indicates that it is information about the character dimensions within the raster. Items marked with (*) should not be changed when editing a character. If after editing the height or width changes, the program will detect this and change the values before writing the new file. Note also that there is a lot of redundant information. This may or may not be eliminated in later versions of the two programs and , once it is determined that the information is truly redundant or unnecessary.

A file contains: Font file information (see the documentation for more details of these fields):

total char :total number of characters checksum (*):matches the checksum in any file that refers to this font. magnification (*): 1000 times the magnification factor at which this font was produced. design size (*): matches the design size in the file. directory pointer (*): pointer to the directory information. pixel id (*): currently = 1001 decimal. max height : not currently used, but available. The height of the tallest raster in the file. max width: also not used. The width of the widest raster in the file.

Character information:

chr code:ascii code of the character in octal. pxl height (*)(+): total height of the raster pxl width (*)(+): total width of the raster x offset (*): offset from upper left hand corner of bounding box y offset (*): offset from upper left hand corner of bounding box tfm width (*): width that the file thinks the character is in es right (-): rightmost pixel in character left (-): leftmost pixel in character depth (-): number of pixels below baseline raster width (-): actual width of the raster from the x offset internal width (-): width of character from x offset right kerning (-): position where right kerning begins top (-): top row of the character data row count (-): height of the character within the raster

Raster information:

+ - origin (-1,-1)

- - x-offset : - y-offset . - white pixels in the raster

* - black pixels in the raster

4  FONT METRIC DATA  CHtoPX §4

Sample raster:  + - .......*........ ......*.*....... .....*...*...... ....*.....*..... :...*********.... .......*........ .......*........ .......*........

5. ⟨ Types 5 ⟩ ≡

font rec = record pxl height : integer ; pxl width: integer ; x offset : integer ; y offset : integer ; raster addr : integer ; tfm width: integer ; chr code: integer ; end;

font tbl type = packed array [1 . . tbl size] of font rec;

See also sections 9 and 22. This code is used in section 2.

6. ⟨ Global Variables 6 ⟩ ≡ end of chr : char ; { end of character marker } font info: font tbl type; save right : integer ; { value read in from chr file } save left : integer ; { value read in from chr file } save depth: integer ; { value read in from chr file } save internal width: integer ; { value read in from chr file } old raster addr : integer ; { value read in from chr file } save kerning : integer ; { value read in from chr file } save top: integer ; { value read in from chr file } save bottom: integer ; { value read in from chr file } save data row count : integer ; { value read in from chr file } save raster width: integer ; { value read in from chr file } total char , checksum, magnification, design size, directory ptr , pixel id , max height , max width: integer ;

See also sections 7, 8, 10, 16, 23, 29, 33, 39, and 45. This code is used in section 2.

7. Suffice it to say that a  file is an ordinary text file. The  format is almost self-explanatory when

you see an example or two. ⟨ Global Variables 6 ⟩ +≡ chr file: text ; page marker : char ; file ok : boolean;

8. Additionally, an error file is provided which contains all error messages for each character. This file can be specified to be the terminal, in which case all the error messages will be displayed when the program is run. ⟨ Global Variables 6 ⟩ +≡ error file: text ; 9. Detailed information about the pxl file appears in the documentation of the companion program, , so it will not be repeated here. ⟨ Types 5 ⟩ +≡

byte = 0 . . 255;

10. ⟨ Global Variables 6 ⟩ +≡ pxl file: packed file of byte;

11. On some systems you may have to do something special to read a packed file of bytes. For example, the following code didn’t work when it was first tried at Stanford, because packed files have to be opened with a special switch setting on the PASCAL that was used. ⟨ Open input and output files 11 ⟩ ≡

rewrite(pxl file);

reset (chr file);

rewrite(error file);

This code is used in section 2.

12. The input may, of course, be all screwed up and not a file at all, so we provide a means of escape.

define abort (#) ≡ begin print ln(#);

          print ln(´ ␣   ␣ ␣   ´    ´ ␣  ␣   ␣   ␣   ␣    ␣    ␣  ␣ ␣   ␣  ´ );

file ok ← false;

end

define error (#) ≡ print ln(#)

6  USEFUL SUBROUTINES  CHtoPX §13

13. Useful subroutines.

14. Max returns the larger of two integers. function max (m, n : integer ): integer ;

begin if m > n then max ← m

else max ← n;

end;

15. Min returns the smaller of two integers. function min(m, n : integer ): integer ;

begin if m > n then min ← n

else min ← m;

end;

16. If we are not at the end of the row, read the next character from chr file. If we are at the end of the row, set ch to a predefined end of line character. If this is the end of the character (and also the end of the page), set an end of page flag. If the character read in matches the end of line character, it is an error, so change it to a period and print out a message. ⟨ Global Variables 6 ⟩ +≡ end of page: boolean; { end of page flag } raster found : boolean; { end of raster flag } ch: char ; { next character read in }

17. procedure get next ch(var ch : char );

begin ch ← end of line;

if ¬eoln(chr file) then read (chr file, ch); if ch = end of chr then

begin end of page ← true; ch ← end of line; end

end;

18. If the header information is missing for a character, or the raster image is too messed up to continue processing this character, then we will skip it. Skip to next page prints an error message, then skips to the beginning of the next character in the file. Usually, each character appears on a separate page. procedure skip to next pg ;

var ch: char ;

begin repeat read (chr file, ch);

until (ch = end of chr ) ∨ eof (chr file);

if eof (chr file) then print ln(´ ␣ ␣ ´ ); end;

§19  CHtoPX  USEFUL SUBROUTINES 7

19. We want to write out the information to the file in 8-bit bytes. Here we convert a 32 bit number into 4 eight-bit bytes and write them out in Big Endian order (highest byte first). procedure write pxl (oneword : integer );

var k, l, m, n: byte; begin k ← oneword div ´ 100000000 ; l ← (oneword div ´ 200000 ) mod 256; m ← (oneword div 256) mod 256; n ← oneword mod 256; write(pxl file, k, l, m, n); end;

20. Here we convert a 16 bit number into 2 eight-bit bytes and write them out in Big Endian order (highest byte first). procedure write half pxl (oneword : integer );

var m, n: byte; begin if oneword < 0 then oneword ← (oneword + 65536); m ← (oneword div 256); n ← (oneword mod 256); write(pxl file, m, n); end;

8  READ FONT INFORMATION FROM CHR FILE  CHtoPX §21

21. Read font information from CHR file. The first step in processing the file is to read in the font file information. Certain fields must be found or the processing can’t continue. These fields originally came from the file, and should not be modified in any way if the file is changed. They include: checksum, magnification, design size, and pixel id . The other fields will be checked by , and if they don’t match the current information in the file, will be updated when the new file is written out. Found info is a flag indicating whether a particular field was found, and found all keeps track of whether the necessary fields were found. File ok checks to see if any information was found at all.

First we declare the constants, types and global variables we will need. There is nothing special about the length of info size; sixteen was chosen simply because all of the information needed fit into that length. ⟨ Constants 21 ⟩ ≡

info size = 16; screen width = 14; { max. no of char that will fit on one screen / 6 }

See also section 32. This code is used in section 2.

22. ⟨ Types 5 ⟩ +≡ infotype = packed array [1 . . info size] of char ;

23. ⟨ Global Variables 6 ⟩ +≡ info: infotype; { header we’re looking for } found info, found all , done: boolean; { flags to indicate what we found } num: integer ; { numeric value associated with the current header } i, j: integer ; { we always need these somewhere }

24. ⟨ Read font info 24 ⟩ ≡ file ok ← false; found all ← true; found info ← true; read hdr (´ ␣ ␣ ␣ ´ , found info); read info(´ ␣ ␣ ␣ ´ , total char , found info, file ok ); read info(´ ␣␣␣␣␣␣␣ ´ , checksum, found info, file ok ); found all ← found all ∧ found info; read info(´ ␣␣ ´ , magnification, found info, file ok ); found all ← found all ∧ found info; read info(´ ␣ ␣␣␣␣ ´ , design size, found info, file ok ); found all ← found all ∧ found info; read info(´ ␣ ␣␣ ´ , directory ptr , found info, file ok ); found all ← found all ∧ found info; read info(´ ␣ ␣␣␣␣␣␣␣ ´ , pixel id , found info, file ok ); found all ← found all ∧ found info; read info(´ ␣ ␣␣␣␣␣ ´ , max height , found info, file ok ); read info(´ ␣ ␣␣␣␣␣␣ ´ , max width, found info, file ok ); ⟨ Can we continue? 25 ⟩

This code is used in section 52.

§25  CHtoPX  READ FONT INFORMATION FROM CHR FILE 9

25. Check to see if the needed information was found, and whether we can continue. If everything was ok, write out the pixel id to the pxl file. ⟨ Can we continue? 25 ⟩ ≡

if ¬file ok then abort (´ ␣ ␣ ␣ ␣ ´ ) else if ¬found all then abort (´ ␣ ␣ ␣ ´ )

else begin write pxl (pixel id ); skip to next pg ; end;

This code is used in section 24.

26. This procedure reads in the header information and the value of the field associated with the header. If the header information does not match the expected header, a switch is set so that the next time this procedure is called, the same field will be checked and no new one read in. This will work fine if there are lines missing; it will not work if there is an extra line or the lines are out of order. If the value is missing, zero is assumed. procedure read info(info : infotype; var val : integer ; var found info : boolean; var ok : boolean);

var i: integer ; name: infotype; { header we’re reading in }

begin if found info then

begin for i ← 1 to info size do if ¬eoln(chr file) then read (chr file, name[i]) else name[i] ← blank ;

if ¬eoln(chr file) then readln(chr file, num) else num ← 0; end;

found info ← name = info; ok ← found info ∨ ok ; if ¬found info then

begin val ← 0; print (info); error (´ ␣ ␣ ␣ ␣ ´ ); end

else val ← num; end;

27. This procedure reads in the file header. If the header is missing, that’s ok, but we’ll print out an error message anyway. We also set found to false, and just in case this is really the next header, we will try to read in a number following the header, and save it for the next go round. procedure read hdr (info : infotype; var found info : boolean);

var i: integer ; name: infotype; { header we’re reading in } begin for i ← 1 to info size do

if ¬eoln(chr file) then read (chr file, name[i]) else name[i] ← blank ;

if name ≠ info then begin error (´ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); error (´ ␣ ␣ ␣ ␣ ␣ ´ ); found info ← false; if ¬eoln(chr file) then read (chr file, num) else num ← 0; end;

readln(chr file); end;

10  READ CHARACTER HEADER  CHtoPX §28

28. Read character header. Now, for each character, the character header is read in, then if the header is ok, the character raster is read, converted to binary, and written out. The information about the character is saved in font info. If the header information is missing the character is skipped. ⟨ Read and save character information 28 ⟩ ≡

⟨ Read character header 30 ⟩ if ¬chr ok then

begin error (´ ␣ ␣ ␣ ␣ ´ ); skip to next pg ; end

else ⟨ Read character raster 34 ⟩

This code is used in section 50.

29. ⟨ Global Variables 6 ⟩ +≡ chr index , temp chr : integer ; chr code: integer ; { value read in from chr file } chr ok : boolean; chr count : integer ; { keeps track of whether we need to start a new line }

§30  CHtoPX  READ CHARACTER HEADER 11

30. Read in the character information using the same procedure as was used for the font information header. Note again, this will work if there are headers missing, but not if they are out of order or there are extra headers.

The only field that is required in the header is the chr code, because without it, we have no idea what character we are processing! If the chr code is missing, we will skip this character and go on to the next. Note that the chr code must be the first line of the header, or we assume that it isn’t there. The other fields will be checked by , and if they don’t match the current information in the file, then will be updated when the new file is written out. If no value can be calculated, such as for tfm width, it will be set to zero. Found info is a flag indicating whether a particular field was found, and chr ok checks to see if any information was found at all. ⟨ Read character header 30 ⟩ ≡

chr ok ← false; found info ← true; read info(´ ␣␣␣␣␣␣␣␣ ´ , chr code, found info, chr ok );

if found info then

begin print (´ ´ , chr code : 1, ´ ´ ); incr (chr count ); if chr count > screen width then

begin print ln(´ ␣´ ); chr count ← 0; end;

⟨ Convert chr code into decimal 31 ⟩ read info(´ ␣␣␣␣␣␣␣␣␣ ´ , font info[chr index ].pxl height , found info, chr ok ); read info(´ ␣␣␣␣␣␣␣␣␣␣ ´ , font info[chr index ].pxl width, found info, chr ok ); read info(´ ␣␣␣␣␣␣␣␣␣␣ ´ , save right , found info, chr ok ); read info(´ ␣␣␣␣␣␣␣␣␣␣␣ ´ , save left , found info, chr ok ); read info(´ ␣␣␣␣␣␣␣␣␣␣ ´ , save depth, found info, chr ok ); read info(´ ␣ ␣␣␣␣␣␣␣ ´ , font info[chr index ].x offset , found info, chr ok ); read info(´ ␣ ␣␣␣␣␣␣␣ ´ , font info[chr index ].y offset , found info, chr ok ); read info(´ ␣ ␣␣␣␣␣␣ ´ , font info[chr index ].tfm width, found info, chr ok ); read info(´ ␣ ␣␣␣ ´ , save raster width, found info, chr ok ); read info(´ ␣ ␣ ´ , save internal width, found info, chr ok ); read info(´ ␣ ␣␣ ´ , save kerning , found info, chr ok ); read info(´ ␣␣␣␣␣␣␣␣␣␣␣␣ ´ , save top, found info, chr ok ); read info(´ ␣␣␣␣␣␣␣␣␣ ´ , save bottom, found info, chr ok ); read info(´ ␣ ␣ ␣ ´ , save data row count , found info, chr ok ); end

else error (´  ´  ´ ␣    ␣  ´ );

This code is used in section 28.

31. ⟨ Convert chr code into decimal 31 ⟩ ≡ chr index ← (chr code div 100) ∗ 64; temp chr ← chr code mod 100; chr index ← chr index + (temp chr div 10) ∗ 8; temp chr ← temp chr mod 10; chr index ← chr index + temp chr + 1; font info[chr index ].chr code ← chr code;

This code is used in section 30.

12  FIND RASTER IMAGE  CHtoPX §32

32. Find raster image. The character raster sits inside a bounding box which contains information about the position of the character within the raster. This outside box may contain any number of rows or columns above or to the left of the character, any or all of which may be blank (but hopefully not, since we are looking for something in these rows and columns). Our first task, therefore, is to find out where the raster is inside this box, and at the same time, to save any information the outside box contains pertaining to the x offset (indicated by a dash), the y offset (a colon), or the origin(a plus) of the raster. ⟨ Constants 21 ⟩ +≡

tbl size = 128; { current maximum number of characters allowed in file } asterisk = ´ ´ ; { represents a pixel that is ‘on’, or black } blank = ´ ␣´ ; { filler for bounding box } period = ´ ´ ; { represents a pixel that is ‘off’, or white } plus = ´ ´ ; { the (0,0) position in the raster } dash = ´ ´ ; { the x offset } bar = ´ ´ ; { the y offset } end of line = ´ ´ ; { marker to signal when we’ve reached the end of a line }

33. ⟨ Global Variables 6 ⟩ +≡ found : (both, origin, x off , none, letter ); { what did we find? } raster addr : integer ; { keeps track of how many words have been written on the pxl file } x offset : integer ; { position of x offset } y offset : integer ; { position of y offset } first column: integer ; { position of the first column of the character raster } bar row : integer ; { row where we found the bar } col index : integer ; { current column } row index : integer ; { current row } dash column: integer ; { column where dash found } plus column: integer ; { column where plus found } plus row : integer ; { row where plus found }

34. It is here that things get sticky. There is no knowing whether either the offset information or the raster itself has been modified since being created by , and there could be all sorts of strange data in it. We will hope for the best, yet proceed with caution. ⟨ Read character raster 34 ⟩ ≡

begin end of page ← false;

row index ← 0;

col index ← 0;

found ← none;

⟨ Skip to beginning of character 36 ⟩

if end of page then

begin error (´ ␣ ␣ ´ ); ⟨ Zero all fields 35 ⟩ end

else begin ⟨ Process raster 40 ⟩ ⟨ Compare old with new values 46 ⟩ end;

end;

This code is used in section 28.

§35  CHtoPX  FIND RASTER IMAGE 13

35. If no raster information was found, no character information will be saved, so all the fields for that character are zeroed out in the font info. ⟨ Zero all fields 35 ⟩ ≡

font info[chr index ].pxl height ← 0; font info[chr index ].pxl width ← 0; font info[chr index ].x offset ← 0; font info[chr index ].y offset ← 0; font info[chr index ].raster addr ← 0; font info[chr index ].tfm width ← 0;

This code is used in section 34.

36. Search for the raster. Read chr file until we reach the first period or asterisk, signalling the beginning of the character itself. Look for a plus, dash, or colon, which will indicate the position of the origin, x-offset, and y-offset, respectively. If no period or asterisk is found, the character doesn’t exist, and no information will be written out to the pxl file. ⟨ Skip to beginning of character 36 ⟩ ≡

dash column ← −1; plus column ← −1; plus row ← −1; bar row ← −1; x offset ← −1; y offset ← −1; first column ← −1; repeat get next ch(ch);

⟨ What is it? 37 ⟩ incr (col index );

until (end of page) ∨ (found = letter );

This code is used in section 34.

37. After we read in the next character, check it to see what it is. If it is a plus , it is the origin; if a dash, it is the x-offset; if it is a colon, it is the y-offset; if it is a blank , it is a place holder; if it is a period or asterisk , it is the beginning of the character raster. At the end of line we increment the row count and reset the column count. ⟨ What is it? 37 ⟩ ≡

case ch of

plus : begin if (found = origin) ∨ (found = both) then error (´ ␣ ␣ ␣ ´ )

else begin if found = x off then found ← both else found ← origin; plus column ← col index ; plus row ← row index ; end;

end; dash: begin if (found = x off ) ∨ (found = both) then error (´ ␣ ␣ ␣ ␣ ´ )

else begin if found = origin then found ← both else found ← x off ; dash column ← col index ; end;

end; bar : bar row ← row index ; blank : do nothing ; asterisk , period : ⟨ Save offset information 38 ⟩; end of line: begin readln(chr file);

incr (row index );

col index ← −1;

end; end;

This code is used in section 36.

38. When we find the first period or asterisk, check to see what state we are in. If we have found the x-offset (dash) or y-offset (colon), save their position, relative to the origin. If the x-offset or origin wasn’t found, assume that they are both zero. If the y-offset wasn’t found, that’s ok, since it could be that we just haven’t gotten to it yet. There will be some number of spaces to the left of the raster (minimum of one) and we will save this number in first column, so that when we start to process the raster image, we know how many spaces to skip before beginning processing. ⟨ Save offset information 38 ⟩ ≡

begin case found of

both, letter : do nothing ; origin: dash column ← plus column; x off : error (´ ␣ ␣ ␣ ␣ ␣ ´ ); none: error (´ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); end; first column ← col index ; found ← letter ; x offset ← dash column − plus column − 1; y offset ← bar row − plus row − 1; end

This code is used in section 37.

§39  CHtoPX  READ CHARACTER RASTER 15

39. Read character raster. Here we read in each row of the character, and convert it into an equivalent binary number. This number must have four bytes of eight bits for a total of 32 positions, so if the row we are reading in does not have a multiple of 32 positions, we have to fill it with zeros so that it does. Each 8 bit number is then written out to the pxl file. This process is repeated for each row in the character. Hopefully, each row will have the same number of characters in it; if they don’t, then the raster is not rectangular, which could indicate a problem. The raster is processed as is, but a warning message is printed out. The character raster is read until either an end of page marker or a blank line is found.

define out (#) ≡ write(pxl file, (# mod 256)); ⟨ Global Variables 6 ⟩ +≡ row , save byte, left , right , top, bottom, num words : integer ; bit : integer ; first line: boolean; { is this the first row of the raster? } last col : boolean; { is this the last col of the raster? } top found : boolean; { have we found the first asterisk? } line width: integer ;

40. ⟨ Process raster 40 ⟩ ≡ top found ← false; left ← max width; right ← 0; top ← 0; bottom ← 0; old raster addr ← raster addr ; save byte ← 0; end of page ← false; row ← row index − 1; line width ← 0; last col ← true; first line ← true; repeat num words ← 0;

row ← row + 1;

repeat incr (num words ); raster found ← false;

for i ← 1 to 4 do { 4 bytes of }

begin for j ← 1 to 8 do { 8 bits each }

⟨ Convert character raster 41 ⟩

if raster found then

begin out (save byte);

save byte ← 0;

end; end;

if raster found then incr (raster addr ); until ch = end of line; if ¬end of page ∧ raster found then ⟨ Find beginning of raster 43 ⟩

until end of page ∨ ¬raster found ; if ¬raster found then skip to next pg ;

This code is used in section 34.

16  READ CHARACTER RASTER  CHtoPX §41

41. Read the next character and convert it. If it is a period, it becomes a zero; if it is an asterisk, it becomes a one; if it is anything else, it is treated as a period. What we are doing here is converting the raster made up of periods and asterisks into a binary number. This number will be saved by writing it out to the pxl file. We are converting it bit by bit, so for each character we read in, we either add a zero or a one onto the end of the number we have calculated so far.

When we get to the end of the line, we also check to see if the line width matches the width of the first line of the character. If it doesn’t, then the character raster is not rectangular, so an error message is printed, but processing continues. ⟨ Convert character raster 41 ⟩ ≡

begin bit ← (j + (i − 1) ∗ 8) + (num words − 1) ∗ 32;

case ch of

asterisk : begin shift and add (save byte); raster found ← true; ⟨ Check extremes 42 ⟩ end;

period : begin shift (save byte); raster found ← true; end;

end of line: begin shift (save byte);

if first line then

begin first line ← false; last col ← false; line width ← bit − 1; end

else if last col then

begin if bit ≠ line width then error (´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); last col ← false; end;

end; blank : shift (save byte); others : begin error (´ ␣ ␣ ␣ ´ );

shift (save byte);

end end; get next ch(ch); end;

This code is used in section 40.

42. We want to keep track of the size of the character within the raster, so we can compare it to the values read in in the header. Left , right , top, and bottom will be used for comparison. ⟨ Check extremes 42 ⟩ ≡

left ← min(bit , left ); right ← max (bit , right ); if ¬top found then

begin top found ← true;

top ← row ;

end; bottom ← row ;

This code is used in section 41.

43. Skip over the space to the left of the raster image which is part of the outside box. If a colon is found, save the row number as the y offset . ⟨ Find beginning of raster 43 ⟩ ≡

begin readln(chr file); for i ← 0 to first column do

begin get next ch(ch);

if ch = bar then y offset ← row ;

end; end;

This code is used in section 40.

44. Check to see if the two fields, num1 and num2 , match. If not, replace the second with the first and set a flag so we’ll know a replacement has been done. procedure check match(var num1 : integer ; var num2 : integer ; var flag : boolean);

begin if num1 ≠ num2 then flag ← false; num2 ← num1 ; end;

45. ⟨ Global Variables 6 ⟩ +≡ width: integer ; { width of the raster we just read in } height : integer ; { height of the raster we just read in } all match: boolean; { used to see if everything matched the values read in }

46. Check to see if the values read in really match the raster. If not, save the raster values and print an error message. ⟨ Compare old with new values 46 ⟩ ≡

all match ← true; width ← right − left + 1; height ← bottom − top + 1; check match(width, font info[chr index ].pxl width, all match); check match(height , font info[chr index ].pxl height , all match); check match(x offset , font info[chr index ].x offset , all match); check match(y offset , font info[chr index ].y offset , all match); font info[chr index ].raster addr ← old raster addr ; if ¬all match then

begin error (´ ´ ); { skip to next line }

error (´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); error (´ ␣ ␣ ␣ ␣ ´ ); end

This code is used in section 34.

18  WRITE PXL FILE INFORMATION  CHtoPX §47

47. Write PXL file information. First, write out all of the font directory information to the pxl file. ⟨ Write directory information to file 47 ⟩ ≡

for i ← 1 to tbl size do begin write half pxl (font info[i].pxl width); write half pxl (font info[i].pxl height ); write half pxl (font info[i].x offset ); write half pxl (font info[i].y offset ); write pxl (font info[i].raster addr ); write pxl (font info[i].tfm width); end;

This code is used in section 51.

48. Finally, write out the font information to the pxl file, and we are done. ⟨ Write font information to file 48 ⟩ ≡

write pxl (checksum); write pxl (magnification); write pxl (design size); all match ← true; check match(raster addr , directory ptr , all match); if ¬all match then error (´ ␣ ␣ ␣ ´ ); write pxl (directory ptr ); write pxl (pixel id ); print ln(´ ␣ ´ );

This code is used in section 51.

§49  CHtoPX  MAIN PROGRAM 19

49. Main program.

50. First read in the file and process the characters. ⟨ Read chr file 50 ⟩ ≡

repeat ⟨ Read and save character information 28 ⟩ until eof (chr file);

This code is used in section 52.

51. Then write out the directory information and font information. ⟨ Write pxl file 51 ⟩ ≡

⟨ Write directory information to file 47 ⟩ ⟨ Write font information to file 48 ⟩

This code is used in section 52.

52. Main program. Here’s where we make it, or don’t.

begin initialize; ⟨ Read font info 24 ⟩ raster addr ← 1; chr count ← 0;

if file ok then

begin ⟨ Read chr file 50 ⟩ ⟨ Write pxl file 51 ⟩ end;

end.

20  SYSTEM-DEPENDENT CHANGES  CHtoPX §53

53. System-dependent changes. This module should be replaced, if necessary, by changes to the program that are necessary to make work at a particular installation. It is usually best to design your change file so that all changes to previous modules preserve the module numbering; then everybody’s version will be consistent with the printed program. More extensive changes, which introduce new modules, can be inserted here; then only the index itself will get a new module number.

§54  CHtoPX  INDEX 21

54. Index. Pointers to error messages appear here together with the section numbers where each identifier is used.

abort : \underline{12}, 25. all match: \underline{45}, 46, 48. almost : 4. asterisk : \underline{32}, 37, 41. banner : \underline{1}, 2. bar : \underline{32}, 37, 43. bar row : \underline{33}, 36, 37, 38. bit : \underline{39}, 41, 42. blank : 26, 27, \underline{32}, 37, 41. boolean: 7, 16, 23, 26, 27, 29, 39, 44, 45. both: 33, 37, 38. bottom: \underline{39}, 40, 42, 46. byte: \underline{9}, 10, 19, 20. ch: \underline{16}, \underline{17}, \underline{18}, 36, 37, 40, 41, 43. char : 6, 7, 16, 17, 18, 22. check match: \underline{44}, 46, 48. checksum: 4, \underline{6}, 21, 24, 48. Chinese characters: 1. chr : 2. chr code: 4, \underline{5}, \underline{29}, 30, 31. chr count : \underline{29}, 30, 52. chr file: \underline{2}, 6, \underline{7}, 11, 16, 17, 18, 26, 27, 29, 36,

37, 43, 50. chr index : \underline{29}, 30, 31, 35, 46. chr ok : 28, \underline{29}, 30. CHtoPX : \underline{2}. col index : \underline{33}, 34, 36, 37, 38. colon: 37. dash: \underline{32}, 37. dash column: \underline{33}, 36, 37, 38. data row count : 4. decr : \underline{3}. depth: 4. design size: 4, \underline{6}, 21, 24, 48. directory pointer : 4. directory ptr : \underline{6}, 24, 48. do nothing : \underline{3}, 37, 38. done: \underline{23}. end of chr : 2, \underline{6}, 17, 18. end of line: 16, 17, \underline{32}, 37, 40, 41. end of page: \underline{16}, 17, 34, 36, 39, 40. eof : 18, 50. eoln: 17, 26, 27. error : \underline{12}, 26, 27, 28, 30, 34, 37, 38, 41, 46, 48. error file: \underline{2}, \underline{8}, 11. false: 12, 24, 27, 30, 34, 40, 41, 44. file ok : \underline{7}, 12, 24, 25, 52. File ok : 21. first column: \underline{33}, 36, 38, 43. first line: \underline{39}, 40, 41. flag : \underline{44}. font info: \underline{6}, 28, 30, 31, 35, 46, 47. font rec: \underline{5}. font tbl type: \underline{5}, 6. found : 27, \underline{33}, 34, 36, 37, 38. found all : 21, \underline{23}, 24, 25. found info: \underline{23}, 24, \underline{26}, \underline{27}, 30. Found info: 21, 30. get next ch: \underline{17}, 36, 41, 43. height : \underline{45}, 46. i: \underline{23}, \underline{26}, \underline{27}. incr : \underline{3}, 30, 36, 37, 40. info: \underline{23}, 26, 27. info size: \underline{21}, 22, 26, 27. infotype: \underline{22}, 23, 26, 27. initialize: \underline{2}, 52. integer : 5, 6, 14, 15, 19, 20, 23, 26, 27, 29,

33, 39, 44, 45. internal width: 4. j: \underline{23}. Japanese characters: 1. k: \underline{19}. last col : \underline{39}, 40, 41. Left : 42. left : 4, \underline{39}, 40, 42, 46. letter : 33, 36, 38. line width: \underline{39}, 40, 41. m: \underline{20}. magnification: 4, \underline{6}, 21, 24, 48. max : \underline{14}, 42. Max : 14. max height : 4, \underline{6}, 24. max width: 4, \underline{6}, 24, 40. min: \underline{15}, 42. Min: 15. name: \underline{26}, \underline{27}. none: 33, 34, 38. num: \underline{23}, 26, 27. num words : \underline{39}, 40, 41. num1 : \underline{44}. num2 : \underline{44}. ok : \underline{26}. old raster addr : \underline{6}, 40, 46. oneword : \underline{19}, 20. oriental characters: 1. origin: 4, 32, 33, 37, 38. others : 41. out : \underline{39}, 40. page marker : 2, \underline{7}. period : \underline{32}, 37, 41.

22  INDEX  CHtoPX §54

pixel id : 4, \underline{6}, 21, 24, 25, 48. plus : \underline{32}, 37. plus column: \underline{33}, 36, 37, 38. plus row : \underline{33}, 36, 37, 38. print : \underline{2}, 26, 30. print ln: \underline{2}, 12, 18, 30, 48. pxl file: \underline{2}, 9, \underline{10}, 11, 19, 20, 25, 33, 36, 39,

41, 47, 48. pxl height : 4, \underline{5}, 30, 35, 46, 47. pxl width: 4, \underline{5}, 30, 35, 46, 47. raster addr : \underline{5}, \underline{33}, 35, 40, 46, 47, 48, 52. raster found : \underline{16}, 40, 41. raster width: 4. read : 17, 18, 26, 27. read hdr : 24, \underline{27}. read info: 24, \underline{26}, 30. readln: 26, 27, 37, 43. reset : 11. rewrite: 11. right : 4, \underline{39}, 40, 42, 46. right kerning : 4. row : \underline{39}, 40, 42, 43. row index : \underline{33}, 34, 37, 40. save bottom: \underline{6}, 30. save byte: \underline{39}, 40, 41. save data row count : \underline{6}, 30. save depth: \underline{6}, 30. save internal width: \underline{6}, 30. save kerning : \underline{6}, 30. save left : \underline{6}, 30. save raster width: \underline{6}, 30. save right : \underline{6}, 30. save top: \underline{6}, 30. screen width: \underline{21}, 30. shift : \underline{3}, 41. shift and add : \underline{3}, 41. Skip to next page: 18. skip to next pg : \underline{18}, 25, 28, 40. system dependencies: 2, 11, 53. tbl size: 5, \underline{32}, 47. temp chr : \underline{29}, 31. text : 7, 8. tfm width: 4, \underline{5}, 30, 35, 47. top: 4, \underline{39}, 40, 42, 46. top found : \underline{39}, 40, 42. total char : 4, \underline{6}, 24. true: 17, 24, 30, 40, 41, 42, 46, 48. val : \underline{26}. width: \underline{45}, 46. write: 2, 19, 20, 39. write half pxl : \underline{20}, 47. write ln: 2. write pxl : \underline{19}, 25, 47, 48. x off : 33, 37, 38. x offset : 4, \underline{5}, 30, 32, \underline{33}, 35, 36, 38, 46, 47. y offset : 4, \underline{5}, 30, 32, \underline{33}, 35, 36, 38, 43, 46, 47.

§54  CHtoPX  NAMES OF THE SECTIONS 23

⟨ Can we continue? 25 ⟩ Used in section 24. ⟨ Check extremes 42 ⟩ Used in section 41.

⟨ Compare old with new values 46 ⟩ Used in section 34.

⟨ Constants 21, 32 ⟩ Used in section 2.

⟨ Convert character raster 41 ⟩ Used in section 40. ⟨ Convert chr code into decimal 31 ⟩ Used in section 30. ⟨ Find beginning of raster 43 ⟩ Used in section 40.

⟨ Global Variables 6, 7, 8, 10, 16, 23, 29, 33, 39, 45 ⟩ Used in section 2.

⟨ Open input and output files 11 ⟩ Used in section 2.

⟨ Process raster 40 ⟩ Used in section 34.

⟨ Read and save character information 28 ⟩ Used in section 50. ⟨ Read character header 30 ⟩ Used in section 28. ⟨ Read character raster 34 ⟩ Used in section 28.

⟨ Read font info 24 ⟩ Used in section 52. ⟨ Read chr file 50 ⟩ Used in section 52.

⟨ Save offset information 38 ⟩ Used in section 37. ⟨ Skip to beginning of character 36 ⟩ Used in section 34.

⟨ Types 5, 9, 22 ⟩ Used in section 2. ⟨ What is it? 37 ⟩ Used in section 36.

⟨ Write directory information to file 47 ⟩ Used in section 51. ⟨ Write font information to file 48 ⟩ Used in section 51.

⟨ Write pxl file 51 ⟩ Used in section 52. ⟨ Zero all fields 35 ⟩ Used in section 34.

The CHtoPX processor

(Version 1, October 1983)

Section Page

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2 Font metric data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 3 Useful subroutines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 6 Read font information from CHR file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 8 Read character header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 10 Find raster image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 12 Read character raster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 15 Write PXL file information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 18 Main program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 19 System-dependent changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 20 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 21

The preparation of this report was supported in part by the National Science Foundation under grants IST-8201926 and MCS-7723738, and by the System Development Foundation. ‘TEX’ is a trademark of the American Mathematical Society.