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
main(argc,argv)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*/
error(string,a1,a2,a3,a4)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
outhex(value)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