1 /* ch2qms.c 1.1 87/02/05 2 * 3 * Font translation to qms-style fonts (QUIC format) from character format. 4 * 5 * Use: ch2qms [ -i -s -b# ] charfile > qmsfile 6 * 7 * Takes input from charfile (which must be in the format written 8 * by one of the xxx2ch programs), converts to qms' QUIC format (with the 9 * baseline version of the format) and writes to stdout. If charfile is 10 * missing, stdin is read. The -i flag tells ch2qms to ignore the 11 * character codes at the start of each glyph definition, and pack the 12 * glyphs in consecutive code positions starting with 0. The -s flag 13 * forces ch2qms to NOT trim off any white space in the glyph map. This 14 * is useful to make stipples of fixed size. The -b flag gives ch2qms 15 * a glyph number to produce a baseline from, replacing it's default 16 * (character #65, `A'). If a "baseline" value isn't given explicitly 17 * in the font, one is calculated by searching for the bottom of the 18 * baseline character. 19 */ 20 21 #include <stdio.h> 22 23 24 #define MAXLINE 300 25 #define RES 300 /* resolution, in pixels per inch */ 26 #define DIRSIZ 256 /* maximum number of characters in font */ 27 #define HEADER "^PY^-\n^F^-\n^DF" 28 29 30 char *calloc(); 31 32 typedef struct { 33 int pwidth; /* printing width of glyph, in bits */ 34 int gwidth; /* width of a glyph, in bits */ 35 int gheight; /* height of glyph */ 36 int hoff; /* from left edge to reference point */ 37 int voff; /* from top edge to reference point */ 38 char *glyph; /* encoded bits of glyph */ 39 } glyphentry; 40 41 42 int code; /* code of character working on */ 43 int width, length; /* dimensions of glyph bit-map */ 44 int maxv, minv, maxh, minh; /* limits of "blackness" in the bit-map */ 45 int maxup = 0; /* most movement above and */ 46 int maxdown = 0; /* below the reference points */ 47 int refv, refh; /* reference point found in glyph */ 48 int lineok; 49 50 int ignorecode = 0; /* option: ignore the character number given */ 51 int stipple = 0; /* option: use whitespace in the glyph */ 52 int height = -1; /* height of every character in the font */ 53 int fontid; /* the "font number" */ 54 int landscape = 0; /* flag: is this a landscape font? */ 55 int version = 0; /* version code */ 56 int baseline = -1; /* baseline of font (if specified) */ 57 int baselinechar = 65; /* character to use to figure baseline from */ 58 int bitwidth; 59 FILE * filep; 60 char buff[MAXLINE][MAXLINE]; 61 char name[5]; 62 char * bitp; 63 glyphentry g[DIRSIZ]; 64 65 66 main(argc, argv) 67 int argc; 68 char **argv; 69 { 70 register int i; 71 register int j; 72 register int codeindex; 73 register char *chp; 74 float par; 75 76 while (argc > 1 && argv[1][0] == '-') { 77 switch(argv[1][1]) { 78 case 'b': 79 baselinechar = atoi(argv[1] + 2); 80 if (baselinechar < 0 || baselinechar >= DIRSIZ) 81 error("baseline character %d out of range", baselinechar); 82 break; 83 case 'i': 84 ignorecode = 1; 85 break; 86 case 's': 87 stipple = 1; 88 break; 89 default: 90 error("%s, unknown option flag", argv[1]); 91 } 92 argc--; argv++; 93 } 94 95 if (argc == 2) { 96 if ((filep = fopen (argv[1], "r")) == NULL) 97 error("can't open file \"%s\"", argv[1]); 98 } else filep = stdin; 99 100 codeindex = 0; 101 102 fgets(buff[0], MAXLINE, filep); 103 if (strcmp(buff[0], "fontheader\n")) 104 error("not a character font file"); 105 106 while (fgets(buff[0], MAXLINE, filep) != NULL) { 107 if (index(buff[0], '\n') == 0) 108 error("input line too long"); 109 110 if (buff[0][0] != ':') { 111 sscanf(buff, "%s %f", buff[1], &par); 112 i = par + 0.5; 113 if (strcmp(buff[1], "rot") == 0) 114 switch (i) { 115 case 1: 116 landscape = 1; 117 break; 118 case 0: 119 landscape = 0; 120 break; 121 default: 122 error("illegal rotation (%d).", i); 123 } 124 else if (strcmp(buff[1], "version") == 0) version = i; 125 else if (strcmp(buff[1], "name") == 0) 126 sscanf(buff[0], "%s %s", buff[1], name); 127 else if (strcmp(buff[1], "linesp") == 0) height = i; 128 else if (strcmp(buff[1], "id") == 0) fontid = i; 129 else if (strcmp(buff[1], "baseline") == 0) baseline = i; 130 else if (strcmp(buff[1], "res") == 0) { 131 if (i != RES) 132 fprintf(stderr,"ch2qms: warning, wrong resolution (%d).\n",i); 133 } /* ignore unrecognized fields */ 134 } else { 135 if (sscanf (buff[0], ":%d, width = %f", &code, &par) != 2) 136 error("bad glyph header, %s", buff[0]); 137 if (ignorecode) codeindex++; else codeindex = code; 138 if (codeindex >= DIRSIZ) 139 error("glyph number (%d) out of range", codeindex); 140 g[codeindex].pwidth = par + 0.5; 141 142 if (fgets(buff[0], MAXLINE, filep) == NULL) 143 error("unexpected end of input"); 144 width = strlen(buff[0]) - 1; 145 minh = width; 146 maxh = 0; 147 refh = minv = -1; 148 149 for (length = 0; *(chp = &(buff[length][0])) != '\n'; length++) { 150 if (length >= MAXLINE) 151 error("not enough space to read in glyph"); 152 lineok = 0; 153 for (i = 0; i <= width; i++, chp++) { 154 switch (*chp) { 155 case '\n': 156 case '\r': 157 lineok = (i == width); 158 case '.': 159 *chp = 0; 160 break; 161 case 'x': 162 *chp = 0; 163 case 'X': 164 if (refh >= 0) 165 error ("glyph %d - two reference points", 166 code); 167 refh = i; 168 refv = length; 169 if (!*chp) break; 170 case '@': 171 case '*': 172 *chp = '\1'; 173 if (minv < 0) minv = length; 174 if (i < minh) minh = i; 175 if (i > maxh) maxh = i; 176 maxv = length; 177 break; 178 default: 179 error("illegal character '%c' in map.", *chp); 180 } /* switch */ 181 } /* for i */ 182 if (!lineok) error("lines not equal length in glyph %d", code); 183 if (fgets(buff[length + 1], MAXLINE, filep) == NULL) 184 error("unexpected end of input"); 185 } /* for length */ 186 187 if (stipple) { /* use the whole box to make a */ 188 minv = 0; /* stipple pattern. */ 189 minh = 0; 190 maxv = length - 1; 191 maxh = width - 1; 192 } 193 194 if (refh < 0) error("no reference point in glyph %d.", code); 195 if (minv < 0) { 196 minv = maxv = refv; 197 minh = maxh = refh; 198 } 199 if (landscape) { 200 if (maxup < width - refh) maxup = width - refh; 201 if (maxdown < refh) maxdown = refh; 202 } else { 203 if (maxup < refv) maxup = refv; 204 if (maxdown < length - refv) maxdown = length - refv; 205 } 206 207 g[codeindex].gwidth = maxh + 1 - minh; 208 g[codeindex].gheight = maxv + 1 - minv; 209 g[codeindex].hoff = refh - minh; 210 g[codeindex].voff = refv - minv; 211 bitp = calloc(((g[codeindex].gwidth+7)/8)*g[codeindex].gheight,1); 212 g[codeindex].glyph = bitp; 213 bitp--; 214 for (i = minv; i <= maxv; i++) { 215 chp = &(buff[i][minh]); 216 bitwidth = 0; 217 for (j = minh; j <= maxh; j++, chp++) { 218 if (--bitwidth < 0) { 219 *++bitp = '\0'; 220 bitwidth = 7; 221 } 222 if (*chp) *bitp |= 1 << bitwidth; 223 } 224 } /* for i */ 225 } /* else */ 226 } /* while */ 227 228 if (height < 0) { 229 height = maxup + maxdown + 1; 230 } 231 if (baseline < 0) { 232 if (g[baselinechar].glyph == (char *) 0) 233 error("no glyph at baseline character %d", baselinechar); 234 if (landscape) { 235 i = g[baselinechar].hoff; 236 j = g[baselinechar].gwidth; 237 if (i < -1 || i > j / 3) { 238 baseline = j; 239 baselinechar = 1 + i; 240 } else { 241 baseline = maxup + 1; 242 baselinechar = 0; 243 } 244 } else { 245 i = g[baselinechar].voff; 246 j = g[baselinechar].gheight; 247 if (i < j - 1 || i > j + 1) { 248 baseline = j; 249 baselinechar = j - i; 250 } else { 251 baseline = maxup + 1; 252 baselinechar = 0; 253 } 254 } 255 } else { 256 baselinechar = 0; 257 } 258 printf(HEADER); 259 printf("%05d%c%d%4s%03d%03dT,\n", fontid, landscape ? 'Y' : 'X', version, 260 name, height, baseline); 261 baseline -= baselinechar; 262 if (landscape) baseline = height - baseline; 263 for (codeindex = 0; codeindex < DIRSIZ; codeindex++) { 264 if (g[codeindex].glyph != (char *) 0) { 265 code = 80; 266 outhex(codeindex); 267 printf("%03d%03d%03d", g[codeindex].pwidth, 268 g[codeindex].gheight, g[codeindex].gwidth); 269 if (landscape) { 270 i = -g[codeindex].voff; 271 j = baseline - g[codeindex].hoff; 272 } else { 273 i = baseline - g[codeindex].voff; 274 j = -g[codeindex].hoff; 275 } 276 if (i < 0) 277 printf("%04d", i); 278 else 279 printf("%03d", i); 280 if (j < 0) 281 printf("%04d", j); 282 else 283 printf("%03d", j); 284 chp = g[codeindex].glyph; 285 for (j = g[codeindex].gheight; j; j--) { 286 if (code > 72) { 287 code = 0; 288 printf("\n"); 289 } 290 for (i = (g[codeindex].gwidth + 7) / 8; i; i--) { 291 outhex(*((unsigned char *) chp++)); 292 code += 2; 293 } 294 if (code % 4) { 295 printf("00"); 296 code += 2; 297 } 298 } 299 printf(",\n"); 300 } 301 } 302 printf("^G\n"); 303 exit(0); 304 } 305 306 307 /*----------------------------------------------------------------------------* 308 | Routine: error (format_string, argument1, argument2.... ) 309 | 310 | Results: fprints a message to standard error, then exits with error 311 | code 1 312 | 313 | Side Efct: This routine does NOT return 314 *----------------------------------------------------------------------------*/ 315 316 /*VARARGS1*/ 317 error(string, a1, a2, a3, a4) 318 char *string; 319 { 320 fprintf(stderr, "ch2qms: "); 321 fprintf(stderr, string, a1, a2, a3, a4); 322 fprintf(stderr, "\n"); 323 exit(1); 324 } 325 326 327 /*----------------------------------------------------------------------------- 328 | Routine: outhex (number) 329 | 330 | Results: prints to standard output, the 2-digit hex value "number" 331 | and does so in capital letters (which printf won't) 332 *----------------------------------------------------------------------------*/ 333 char hexness[] = "0123456789ABCDEF"; 334 335 outhex(value) 336 int value; 337 { 338 register int i = value; 339 340 printf("%c", hexness[(i>>4)&15]); 341 printf("%c", hexness[i&15]); 342 } 343