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