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 
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*/
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 
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