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
main(argc,argv)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
bound(i)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
vwrite(buf,bufsize)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*/
error(string,a1,a2,a3,a4)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