1 /* ch2vft.c 1.6 85/07/03 2 * 3 * Font translation to vfont format from character format. 4 * 5 * Use: ch2vft [ -i -s ] charfile > vfontfile 6 * 7 * Takes input from charfile (which must be in the format written 8 * by one of the xxx2ch programs), converts to vfont format and writes it 9 * to stdout. If charfile is missing, stdin is read. The -i flag tells 10 * ch2vft to ignore the character codes at the start of each glyph 11 * definition, and pack the glyphs in consecutive code positions starting 12 * with 0. The -s flag forces ch2vft to include the whole bit-map that 13 * defines the glyph. Normally, it is trimmed of white space. This is 14 * usefull for making stipple patterns of fixed size. 15 */ 16 17 #include <stdio.h> 18 #include <vfont.h> 19 20 21 #ifdef sun 22 #define RES 120 /* for SUN vfont, resolution is 120 */ 23 #else 24 #define RES 200 /* for vfont, resolution is 200 */ 25 #endif 26 #define MAXLINE 200 27 #define GLYPHSPACE (MAXLINE * MAXLINE) 28 #define MAGICNO 0436 29 #define DIRSIZ 256 /* vfonts MUST have 256 entries */ 30 #define DIMLIMIT 128 31 32 33 char * malloc(); 34 35 struct dispatch g[DIRSIZ]; /* directory of glyph definitions */ 36 struct header head; /* font file header */ 37 38 int code; 39 int width, length, maxv, minv, maxh, minh, refv, refh; 40 int fileaddr; 41 42 int ignorecode = 0; 43 int stipple = 0; 44 FILE * filep; 45 char ibuff[MAXLINE]; 46 char ebuff[MAXLINE]; 47 char * glyphs[DIRSIZ]; 48 char charbits[GLYPHSPACE]; /* place to store bits for a glyph */ 49 50 51 main(argc,argv) 52 int argc; 53 char **argv; 54 { 55 register int i; 56 register int j; 57 register int codeindex; 58 register char *chp; 59 register char *bitp; 60 float par; 61 62 63 head.magic = MAGICNO; 64 head.maxx = head.maxy = head.xtend = 0; 65 while (argc > 1 && argv[1][0] == '-') { 66 switch(argv[1][1]) { 67 case 'i': 68 ignorecode = 1; 69 break; 70 71 case 's': 72 stipple = 1; 73 break; 74 default: 75 error("%s, unknown option flag", argv[1]); 76 } 77 argc--; argv++; 78 } 79 80 if (argc == 2) { 81 if ((filep = fopen (argv[1], "r")) == NULL) 82 error("can't open file \"%s\"", argv[1]); 83 } else filep = stdin; 84 85 codeindex = 0; 86 for (i = 0; i < DIRSIZ; glyphs[i++] = (char *) 0); 87 88 fgets(ibuff, MAXLINE, filep); 89 if (strcmp(ibuff, "fontheader\n")) 90 error("not a character font file"); 91 92 while (fgets(ibuff, MAXLINE, filep) != NULL) { 93 if (index(ibuff, '\n') == 0) 94 error("input line too long"); 95 96 if (ibuff[0] != ':') { 97 sscanf (ibuff, "%s %f", ebuff, &par); 98 if (strcmp(ebuff, "res") == 0) { 99 if (((int) (par + 0.5)) != RES) 100 fprintf(stderr, "ch2vft warning: wrong resolution (%d).\n", 101 (int) (par + 0.5) ); 102 } 103 } else { 104 if (sscanf (ibuff, ":%d, width = %f", &code, &par) != 2) 105 error("bad glyph header, %s", ibuff); 106 if (ignorecode) codeindex++; else codeindex = code; 107 if (codeindex < 0 || codeindex >= DIRSIZ) 108 error("code (%d) out of range", codeindex); 109 g[codeindex].width = par + 0.5; 110 111 chp = &charbits[0]; 112 if (fgets(chp, MAXLINE, filep) == NULL) 113 error("unexpected end of input"); 114 width = strlen(chp) - 1; 115 minh = width; 116 maxh = 0; 117 refv = minv = -1; 118 119 for (length = 0; *chp != '\n'; length++) { 120 if ((length + 1) * width > GLYPHSPACE) 121 error ("out of glyph space"); 122 for (i = 0; i < width; i++, chp++) { 123 switch (*chp) { 124 case '.': 125 break; 126 case 'x': 127 refh = i; 128 refv = length; 129 *chp = '.'; 130 break; 131 case 'X': 132 refh = i; 133 refv = length; 134 case '@': 135 case '*': 136 maxv = length; 137 if (minv < 0) minv = length; 138 if (i < minh) minh = i; 139 if (i > maxh) maxh = i; 140 break; 141 default: 142 error("illegal character '%c' in map.", *chp); 143 } /* switch */ 144 } /* for i */ 145 if (fgets(chp, MAXLINE, filep) == NULL) 146 error("unexpected end of input"); 147 } /* for length */ 148 149 if (stipple) { /* force whole box if making stipples */ 150 minv = 0; 151 minh = 0; 152 maxv = length - 1; 153 maxh = width - 1; 154 } 155 156 if (refv < 0) error("no reference point in glyph %d.", code); 157 if (minv < 0) { 158 minv = maxv = refv; 159 minh = maxh = refh; 160 } 161 g[codeindex].up = bound(refv - minv); 162 g[codeindex].down = bound(maxv + 1 - refv); 163 g[codeindex].right = bound(maxh + 1 - refh); 164 g[codeindex].left = bound(refh - minh); 165 #ifdef sun 166 g[codeindex].nbytes = (maxv+1-minv) * ((maxh+16-minh) / 16) * 2; 167 #else 168 g[codeindex].nbytes = (maxv + 1 - minv) * ((maxh + 8 - minh) >> 3); 169 #endif 170 171 /* convert from characters to bits */ 172 bitp = (glyphs[codeindex] = malloc(g[codeindex].nbytes)) - 1; 173 for (i = minv; i <= maxv; i++) { 174 register int bitwidth; 175 176 chp = &charbits[0] + width * i + minh; 177 bitwidth = 0; 178 for (j = minh; j <= maxh; j++, chp++) { 179 if (--bitwidth < 0) { 180 *++bitp = '\0'; 181 bitwidth = 7; 182 } 183 if (*chp != '.') *bitp |= 1 << bitwidth; 184 } 185 #ifdef sun 186 if (!((bitp - glyphs[codeindex]) & 1)) *++bitp = '\0'; 187 #endif 188 } /* for i */ 189 } /* else */ 190 } /* while */ 191 192 fileaddr = 0; 193 for (i = 0; i < DIRSIZ; i++) { 194 if (glyphs[i] == (char *) 0) { 195 g[i].nbytes = 0; 196 } else { 197 g[i].addr = fileaddr; 198 fileaddr += g[i].nbytes; 199 if (g[i].up > head.maxy) head.maxy = g[i].up; 200 if (g[i].down > head.xtend) head.xtend = g[i].down; 201 if (((int) g[i].left + g[i].right) > head.maxx) 202 head.maxx = g[i].left + (int) g[i].right; 203 } 204 } 205 head.size = fileaddr; 206 207 vwrite((char *) &head, sizeof(head)); 208 vwrite((char *) &(g[0]), sizeof(g)); 209 for (i = 0; i < DIRSIZ; i++) 210 if (glyphs[i] != (char *) 0) 211 vwrite(glyphs[i], g[i].nbytes); 212 exit(0); 213 } 214 215 216 /*----------------------------------------------------------------------------* 217 | Routine: bound (value) 218 | 219 | Results: checks to make sure that the dimensions of a glyph fit into 220 | the vfont format's limitations. The up, down, right, and left 221 | fields must fit into a byte!), but can be signed. 222 *----------------------------------------------------------------------------*/ 223 224 bound(i) 225 { 226 if(i < DIMLIMIT && i >= -DIMLIMIT) return i; 227 error ("dimension out of range"); 228 } 229 230 231 /*----------------------------------------------------------------------------* 232 | Routine: vwrite (buffer, buffer_size) 233 | 234 | Results: writes out character array "buffer" of size "buffer_size" 235 | to standard output in small enough chunks that a pipe could 236 | handle them. 237 | 238 | Bugs: this routine shouldn't be needed 239 *----------------------------------------------------------------------------*/ 240 241 vwrite(buf, bufsize) 242 char *buf; 243 int bufsize; 244 { 245 int tsize = 0; 246 247 while (bufsize) { 248 buf += tsize; 249 tsize = bufsize > BUFSIZ ? BUFSIZ : bufsize; 250 if ((tsize = write(1, buf, tsize)) < 0) { 251 perror("ch2vft: write failed"); 252 exit(-1); 253 } 254 bufsize -= tsize; 255 } 256 } 257 258 259 /*----------------------------------------------------------------------------* 260 | Routine: error (format_string, argument1, argument2.... ) 261 | 262 | Results: fprints a message to standard error, then exits with error 263 | code 1 264 | 265 | Side Efct: This routine does NOT return 266 *----------------------------------------------------------------------------*/ 267 268 /*VARARGS1*/ 269 error(string, a1, a2, a3, a4) 270 char *string; 271 { 272 fprintf(stderr, "ch2vft: "); 273 fprintf(stderr, string, a1, a2, a3, a4); 274 fprintf(stderr, "\n"); 275 exit(1); 276 } 277