Jack Moskowitz (PAD) <jackm@ARDC.ARPA> (01/08/85)
I am looking for machine readable character font definitions for a graphics package that we are generating. I know that that this has been done many times before and I dont relish the graph paper approach. Any help would be greatly appreciated.
Doug Gwyn (VLD/VMB) <gwyn@Brl-Vld.ARPA> (01/08/85)
/* symbol -- software character generator subroutine last edit: 26-Nov-1984 D A Gwyn Function: This routine plots an ASCII character string as vector strokes. Calling sequence: void symbol( char *string, // -> NUL-terminated string int llcx, // X position of text LLC int llcy, // X position of text LLC int height, // text height & spacing double theta // rotation (degrees CCW) ); Calls: void move( int x, int y ); // PLOT(3X) move-pen void cont( int x, int y ); // PLOT(3X) draw */ #include <math.h> extern void cont(), move(); /* STROKE TABLES The stroke[] table contains encodings for all vector strokes needed to draw each character at a standard size. Actual plot output is of course properly positioned, scaled, and rotated. To keep code size small, variable-length entries are used; each character stroke sequence is terminated by a 0 datum. Pointers to the appropriate data for every character is stored into sstroke[] during a one-time initialization. The prototypes are constrained to a 4 x 6 unit area, except for occasional descenders up to 2 units below the baseline. All visible strokes should be "basic" vectors (in directions that are integral multiples of 45 degrees) for best overall results on most devices, especially with small character height. The first 16 "control" characters are plotted as non-standard extra symbols, the next 16 produce Calcomp "centered plotting symbols" (not centered here!), and the final 96 characters are plotted as corresponding ASCII graphics (DEL plots as a grid). A prototype stroke is encoded as 8 bits SVXXXYYY: S = 0 if YYY is correct as is 1 if YYY needs to have 2 subtracted V = 0 if stroke is invisible (move) 1 if stroke is visible (draw) XXX = final X coord of stroke (0..4) YYY = final Y coord of stroke (0..6) */ /* bit masks for fields in stroke vector */ #define S 0200 #define V 0100 #define XXX 0070 #define YYY 0007 #define XJUST 3 /* bits to the right of XXX */ /* stroke vectors for all characters */ static char stroke[] = { /*NUL*/ 0003, 0105, 0123, 0143, 0141, 0121, 0125, 0, /*SOH*/ 0006, 0115, 0112, 0142, 0022, 0121, 0141, 0140, 0120, 0013, 0133, 0034, 0114, 0015, 0126, 0, /*STX*/ 0021, 0125, 0105, 0103, 0123, 0141, 0143, 0, /*ETX*/ 0012, 0114, 0034, 0104, 0106, 0126, 0124, 0033, 0113, 0021, 0141, 0042, 0122, 0120, 0, /*EOT*/ 0005, 0125, 0134, 0145, 0143, 0023, 0125, 0015, 0113, 0, /*ENQ*/ 0011, 0131, 0142, 0144, 0135, 0115, 0104, 0102, 0111, 0012, 0114, 0134, 0133, 0113, 0023, 0132, 0, /*ACK*/ 0011, 0131, 0142, 0144, 0135, 0115, 0104, 0102, 0111, 0034, 0114, 0112, 0132, 0, /*BEL*/ 0021, 0122, 0142, 0133, 0134, 0124, 0125, 0024, 0114, 0113, 0102, 0122, 0, /*BS */ 0012, 0103, 0114, 0003, 0143, 0, /*HT */ 0003, 0143, 0034, 0143, 0132, 0, /*LF */ 0012, 0121, 0132, 0021, 0125, 0, /*VT */ 0021, 0125, 0014, 0125, 0134, 0, /*FF */ 0012, 0121, 0132, 0021, 0125, 0014, 0125, 0134, 0, /*CR */ 0012, 0103, 0114, 0003, 0143, 0034, 0143, 0132, 0, /*SO */ 0004, 0124, 0126, 0106, 0104, 0014, 0112, 0142, 0034, 0130, 0, /*SI */ 0021, 0123, 0013, 0115, 0025, 0105, 0003, 0123, 0141, 0143, 0, /*DLE*/ 0023, 0125, 0145, 0141, 0101, 0105, 0125, 0, /*DC1*/ 0023, 0125, 0135, 0144, 0142, 0131, 0111, 0102, 0104, 0115, 0125, 0, /*DC2*/ 0023, 0124, 0142, 0102, 0124, 0, /*DC3*/ 0021, 0125, 0003, 0143, 0, /*DC4*/ 0001, 0145, 0005, 0141, 0, /*NAK*/ 0023, 0125, 0143, 0121, 0103, 0125, 0, /*SYN*/ 0021, 0125, 0143, 0103, 0125, 0, /*ETB*/ 0001, 0145, 0105, 0141, 0, /*CAN*/ 0005, 0145, 0101, 0141, 0, /*EM */ 0023, 0121, 0005, 0123, 0145, 0, /*SUB*/ 0023, 0145, 0034, 0132, 0141, 0032, 0112, 0101, 0012, 0114, 0105, 0014, 0134, 0, /*ESC*/ 0001, 0145, 0025, 0121, 0041, 0105, 0003, 0143, 0, /*FS */ 0001, 0141, 0105, 0145, 0101, 0, /*GS */ 0021, 0125, 0, /*RS */ 0023, 0125, 0024, 0142, 0102, 0124, 0021, 0122, 0144, 0104, 0122, 0, /*US */ 0023, 0143, 0, /*SP */ 0, /* ! */ 0020, 0121, 0022, 0126, 0, /* " */ 0014, 0116, 0036, 0134, 0, /* # */ 0010, 0116, 0036, 0130, 0042, 0102, 0004, 0144, 0, /* $ */ 0002, 0111, 0131, 0142, 0133, 0113, 0104, 0115, 0135, 0144, 0026, 0120, 0, /* % */ 0001, 0145, 0025, 0114, 0105, 0116, 0125, 0032, 0141, 0130, 0121, 0132, 0, /* & */ 0040, 0104, 0105, 0116, 0125, 0124, 0102, 0101, 0110, 0120, 0142, 0, /* ' */ 0014, 0136, 0, /* ( */ 0030, 0112, 0114, 0136, 0, /* ) */ 0010, 0132, 0134, 0116, 0, /* * */ 0001, 0145, 0025, 0121, 0041, 0105, 0, /* + */ 0021, 0125, 0003, 0143, 0, /* , */ 0211, 0120, 0121, 0, /* - */ 0003, 0143, 0, /* . */ 0020, 0121, 0, /* / */ 0001, 0145, 0, /* 0 */ 0001, 0145, 0136, 0116, 0105, 0101, 0110, 0130, 0141, 0145, 0, /* 1 */ 0010, 0130, 0020, 0126, 0115, 0, /* 2 */ 0005, 0116, 0136, 0145, 0144, 0100, 0140, 0, /* 3 */ 0001, 0110, 0130, 0141, 0142, 0133, 0144, 0145, 0136, 0116, 0105, 0023, 0133, 0, /* 4 */ 0030, 0136, 0024, 0102, 0142, 0, /* 5 */ 0001, 0110, 0130, 0141, 0143, 0134, 0114, 0103, 0106, 0146, 0, /* 6 */ 0002, 0113, 0133, 0142, 0141, 0130, 0110, 0101, 0105, 0116, 0136, 0145, 0, /* 7 */ 0006, 0146, 0145, 0112, 0110, 0, /* 8 */ 0013, 0102, 0101, 0110, 0130, 0141, 0142, 0133, 0113, 0104, 0105, 0116, 0136, 0145, 0144, 0133, 0, /* 9 */ 0001, 0110, 0130, 0141, 0145, 0136, 0116, 0105, 0104, 0113, 0133, 0144, 0, /* : */ 0020, 0121, 0023, 0124, 0, /* ; */ 0211, 0120, 0121, 0023, 0124, 0, /* < */ 0030, 0103, 0136, 0, /* = */ 0002, 0142, 0044, 0104, 0, /* > */ 0010, 0143, 0116, 0, /* ? */ 0005, 0116, 0136, 0145, 0144, 0122, 0021, 0120, 0, /* @ */ 0031, 0133, 0124, 0113, 0112, 0121, 0131, 0142, 0144, 0135, 0115, 0104, 0101, 0110, 0130, 0, /* A */ 0104, 0126, 0144, 0140, 0042, 0102, 0, /* B */ 0130, 0141, 0142, 0133, 0144, 0145, 0136, 0106, 0100, 0003, 0133, 0, /* C */ 0045, 0136, 0116, 0105, 0101, 0110, 0130, 0141, 0, /* D */ 0130, 0141, 0145, 0136, 0106, 0100, 0, /* E */ 0003, 0133, 0046, 0106, 0100, 0140, 0, /* F */ 0106, 0146, 0033, 0103, 0, /* G */ 0022, 0142, 0141, 0130, 0110, 0101, 0105, 0116, 0136, 0145, 0, /* H */ 0106, 0046, 0140, 0043, 0103, 0, /* I */ 0010, 0130, 0020, 0126, 0016, 0136, 0, /* J */ 0001, 0110, 0130, 0141, 0146, 0, /* K */ 0106, 0046, 0102, 0013, 0140, 0, /* L */ 0006, 0100, 0140, 0, /* M */ 0106, 0124, 0146, 0140, 0, /* N */ 0106, 0005, 0141, 0040, 0146, 0, /* O */ 0010, 0130, 0141, 0145, 0136, 0116, 0105, 0101, 0110, 0, /* P */ 0106, 0136, 0145, 0144, 0133, 0103, 0, /* Q */ 0010, 0130, 0141, 0145, 0136, 0116, 0105, 0101, 0110, 0022, 0140, 0, /* R */ 0106, 0136, 0145, 0144, 0133, 0103, 0013, 0140, 0, /* S */ 0001, 0110, 0130, 0141, 0142, 0133, 0113, 0104, 0105, 0116, 0136, 0145, 0, /* T */ 0020, 0126, 0006, 0146, 0, /* U */ 0006, 0101, 0110, 0130, 0141, 0146, 0, /* V */ 0006, 0102, 0120, 0142, 0146, 0, /* W */ 0006, 0100, 0122, 0140, 0146, 0, /* X */ 0101, 0145, 0146, 0006, 0105, 0141, 0140, 0, /* Y */ 0020, 0123, 0105, 0106, 0046, 0145, 0123, 0, /* Z */ 0040, 0100, 0101, 0145, 0146, 0106, 0013, 0133, 0, /* [ */ 0030, 0110, 0116, 0136, 0, /* \ */ 0005, 0141, 0, /* ] */ 0010, 0130, 0136, 0116, 0, /* ^ */ 0004, 0126, 0144, 0, /* _ */ 0201, 0341, 0, /* ` */ 0016, 0134, 0, /* a */ 0003, 0114, 0134, 0143, 0140, 0042, 0112, 0101, 0110, 0130, 0141, 0, /* b */ 0106, 0001, 0110, 0130, 0141, 0143, 0134, 0114, 0103, 0, /* c */ 0043, 0134, 0114, 0103, 0101, 0110, 0130, 0141, 0, /* d */ 0043, 0134, 0114, 0103, 0101, 0110, 0130, 0141, 0040, 0146, 0, /* e */ 0002, 0142, 0143, 0134, 0114, 0103, 0101, 0110, 0130, 0141, 0, /* f */ 0010, 0115, 0126, 0136, 0145, 0034, 0104, 0, /* g */ 0201, 0310, 0330, 0341, 0144, 0041, 0130, 0110, 0101, 0103, 0114, 0134, 0143, 0, /* h */ 0106, 0003, 0114, 0134, 0143, 0140, 0, /* i */ 0020, 0124, 0114, 0025, 0126, 0, /* j */ 0201, 0310, 0330, 0341, 0144, 0045, 0146, 0, /* k */ 0106, 0044, 0100, 0022, 0140, 0, /* l */ 0020, 0126, 0116, 0, /* m */ 0104, 0003, 0114, 0123, 0120, 0040, 0143, 0134, 0123, 0, /* n */ 0104, 0003, 0114, 0134, 0143, 0140, 0, /* o */ 0010, 0130, 0141, 0143, 0134, 0114, 0103, 0101, 0110, 0, /* p */ 0001, 0110, 0130, 0141, 0143, 0134, 0114, 0103, 0004, 0300, 0, /* q */ 0041, 0130, 0110, 0101, 0103, 0114, 0134, 0143, 0044, 0340, 0, /* r */ 0104, 0003, 0114, 0134, 0143, 0, /* s */ 0001, 0110, 0130, 0141, 0132, 0112, 0103, 0114, 0134, 0143, 0, /* t */ 0004, 0134, 0015, 0111, 0120, 0130, 0141, 0, /* u */ 0004, 0101, 0110, 0130, 0141, 0040, 0144, 0, /* v */ 0004, 0102, 0120, 0142, 0144, 0, /* w */ 0004, 0101, 0110, 0121, 0022, 0121, 0130, 0141, 0144, 0, /* x */ 0144, 0004, 0140, 0, /* y */ 0201, 0310, 0330, 0341, 0144, 0004, 0101, 0110, 0130, 0141, 0, /* z */ 0004, 0144, 0100, 0140, 0, /* { */ 0030, 0121, 0122, 0113, 0124, 0125, 0136, 0, /* | */ 0020, 0126, 0, /* } */ 0010, 0121, 0122, 0133, 0124, 0125, 0116, 0, /* ~ */ 0005, 0116, 0134, 0145, 0, /*DEL*/ 0140, 0146, 0106, 0100, 0010, 0116, 0026, 0120, 0030, 0136, 0 }; /* pointers to start of stroke data for each character */ static char *sstroke[128] = { (char *)0 }; /* CONSTANTS */ #define STDHT 6.0 /* prototype height */ #define CHSPAC 6 /* prototype text spacing */ #define DEGRAD 57.29577951308232087679815481410517033240547246656424 /* degrees per radian */ #define ASCMASK 0177 /* 7-bit ASCII mask */ #define NUL '\0' /* string terminator */ /* GLOBAL DATA */ static double xorg, yorg; /* text LLC coordinates */ static double symcos, symsin; /* transformation coeffs */ /* ENTRY POINT */ void symbol( string, llcx, llcy, height, theta ) char *string; /* -> NUL-terminated string */ int llcx, llcy; /* coordinates of text LLC */ int height; /* text height & spacing */ double theta; /* rotation (degrees CCW) */ { /* initialize starting stroke pointers upon first entry only */ if ( sstroke[0] == (char *)0 ) { register int code; /* ASCII code values */ register char *sp = stroke; /* -> stroke data */ for ( code = 0; code < 128; ++code ) { sstroke[code] = sp; /* starts here */ while ( *sp++ != (char)0 ) ; /* 0 terminates the data */ } } /* set up global parameters for text */ { double angle; /* rotation (radians CCW) */ double ht; /* normalized height */ xorg = (double)llcx; /* text origin (LLC) */ yorg = (double)llcy; ht = (double)height / STDHT; angle = theta / DEGRAD; symcos = cos( angle ) * ht; symsin = sin( angle ) * ht; } /* look up strokes for each character and plot them */ { extern void plot(); /* move/draw routine */ register int c; /* char from ASCII string */ /* also used for stroke data */ register int cornx; /* proto X of cell corner */ for ( cornx = 0; (c = (int)*string++) != NUL; /* next char */ cornx += CHSPAC ) { register char *sp = sstroke[c & ASCMASK]; /* -> stroke data */ /* get to character cell LLC */ plot( cornx, 0, 0 ); /* no move optimization is done */ /* draw the strokes starting at LLC */ while ( c = (int)*sp++ ) /* get stroke */ plot( cornx + ((c & XXX) >> XJUST), (c & YYY) - ((c & S) ? 2 : 0), (c & V) ); /* move or draw */ } } } static void plot( dx, dy, vis ) /* plot adjusted stroke */ int dx, dy; /* unrot pos rel to text LLC */ int vis; /* nonzero => visible */ { /* transform prototype coordinates to actual plot coordinates */ double xf = (double)dx; double yf = (double)dy; int posx = (int)(xorg + xf * symcos - yf * symsin + 0.5); int posy = (int)(yorg + yf * symcos + xf * symsin + 0.5); /* no arithmetic overflow checking is done */ if ( vis == 0 ) move( posx, posy ); /* move pen */ /* no move optimization is done */ else cont( posx, posy ); /* draw */ }