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