1 /* ch2rst.c 1.7 86/03/04
2 *
3 * Font translation to Imagen-style fonts (RST format) from character format.
4 *
5 * Use: ch2rst [ -i -s ] charfile > rstfile
6 *
7 * Takes input from charfile (which must be in the format written
8 * by one of the xxx2ch programs), converts to rst format and writes to
9 * stdout. If charfile is missing, stdin is read. The -i flag tells
10 * ch2rst 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 ch2rst to NOT trim off any white space in
13 * the glyph map. This is usefull to make stipples of fixed size.
14 */
15
16 #include <stdio.h>
17 #include "rst.h"
18
19
20 #define PREAMBLE 44 /* size of preamble */
21 #define STRINGS 2 /* length of strings at pre. */
22 #define STARTGLYPH PREAMBLE + STRINGS
23 #define MAXLINE 300
24 #define GLYPHSPACE (MAXLINE * MAXLINE)
25 #define wr1(x) putchar(x)
26
27
28 char * malloc();
29
30 glyph_dir g[DIRSIZ]; /* directory of glyph definitions */
31 preamble p; /* set of variables for preamble */
32 double widthtofix; /* fix conversion factor */
33 double wordsptemp; /* holds wordsp "fix" `til res. is known */
34 double linesptemp; /* holds linesp "fix" `til res. is known */
35
36 int code; /* read in code for a glyph */
37 int width, length; /* width and length of read-in matrix */
38 int maxv, minv, maxh, minh; /* extent of "blackness" in glyph */
39 int refv, refh; /* reference point in matrix */
40 int bitwidth;
41
42 int ignorecode = 0; /* flag: ignore the code number; successive */
43 int stipple = 0; /* flag: don't eliminate white-space */
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 while (argc > 1 && argv[1][0] == '-') {
63 switch(argv[1][1]) {
64 case 'i':
65 ignorecode = 1;
66 break;
67
68 case 's':
69 stipple = 1;
70 break;
71 default:
72 error("%s, unknown option flag", argv[1]);
73 }
74 argc--; argv++;
75 }
76
77 if (argc > 2)
78 error("too many arguments");
79 if (argc == 2) {
80 if ((filep = fopen (argv[1], "r")) == NULL)
81 error("can't open file \"%s\"", argv[1]);
82 } else filep = stdin;
83
84 codeindex = 0;
85 for (i = 0; i < DIRSIZ; glyphs[i++] = (char *) 0);
86
87 fgets(ibuff, MAXLINE, filep);
88 if (strcmp(ibuff, "fontheader\n"))
89 error("not a character font file");
90
91 while (fgets(ibuff, MAXLINE, filep) != NULL) {
92 if (index(ibuff, '\n') == 0)
93 error("input line too long");
94
95 if (ibuff[0] != ':') {
96 sscanf (ibuff, "%s %f", ebuff, &par);
97 if (strcmp(ebuff, "size") == 0) p.p_size = par + 0.5;
98 else if (strcmp(ebuff, "version") == 0) {
99 if (p.p_version = par + 0.5)
100 error("wrong version (%d) for Font file.", p.p_version);
101 } else if (strcmp(ebuff, "mag") == 0) p.p_mag = par + 0.5;
102 else if (strcmp(ebuff, "desiz") == 0) p.p_desiz = par / FIX + 0.5;
103 else if (strcmp(ebuff, "linesp") == 0) linesptemp = par;
104 else if (strcmp(ebuff, "wordsp") == 0) wordsptemp = par;
105 else if (strcmp(ebuff, "rot") == 0) p.p_rot = par + 0.5;
106 else if (strcmp(ebuff, "cadv") == 0) p.p_cadv = par + 0.5;
107 else if (strcmp(ebuff, "ladv") == 0) p.p_ladv = par + 0.5;
108 else if (strcmp(ebuff, "id") == 0) p.p_id = par + 0.5;
109 else if (strcmp(ebuff, "res") == 0) p.p_res = par + 0.5;
110 /* ignore unrecognized fields */
111 } else {
112 /* set up for real resolution of font file */
113 if (p.p_mag)
114 widthtofix = 1000.0 / (FIXIN * p.p_res * p.p_mag);
115 else
116 widthtofix = (1.0 / (FIXIN * p.p_res));
117 p.p_wordsp = wordsptemp * widthtofix + 0.5;
118 p.p_linesp = linesptemp * widthtofix + 0.5;
119
120 if (sscanf (ibuff, ":%d, width = %f", &code, &par) != 2)
121 error("bad glyph header, %s", ibuff);
122 if (ignorecode) codeindex++; else codeindex = code;
123 g[codeindex].g_pwidth = par * widthtofix + 0.5;
124
125 chp = &charbits[0];
126 if (fgets(chp, MAXLINE, filep) == NULL)
127 error("unexpected end of input");
128 width = strlen(chp) - 1;
129 minh = width;
130 maxh = 0;
131 refv = minv = -1;
132
133 for (length = 0; *chp != '\n'; length++) {
134 if ((length + 1) * width > GLYPHSPACE)
135 error ("out of glyph space");
136 for (i = 0; i < width; i++, chp++) {
137 switch (*chp) {
138 case '.':
139 break;
140 case 'x':
141 if (refv != -1)
142 error("two reference points in glyph %d",code);
143 refh = i;
144 refv = length;
145 *chp = '.';
146 break;
147 case 'X':
148 if (refv != -1)
149 error("two reference points in glyph %d",code);
150 refh = i;
151 refv = length;
152 case '@':
153 case '*':
154 maxv = length;
155 if (minv < 0) minv = length;
156 if (i < minh) minh = i;
157 if (i > maxh) maxh = i;
158 break;
159 default:
160 error("illegal character '%c' in map.", *chp);
161 } /* switch */
162 } /* for i */
163 if (*chp != '\n')
164 error("not all lines equal length in glyph %d", code);
165 if (fgets(chp, MAXLINE, filep) == NULL)
166 error("unexpected end of input");
167 } /* for length */
168
169 if (stipple) { /* use the whole box to make a */
170 minv = 0; /* stipple pattern. */
171 minh = 0;
172 maxv = length - 1;
173 maxh = width - 1;
174 }
175
176 if (refv < 0) error("no reference point in glyph %d.", code);
177 if (minv < 0) {
178 minv = maxv = refv;
179 minh = maxh = refh;
180 }
181 g[codeindex].g_height = maxv + 1 - minv;
182 g[codeindex].g_width = maxh + 1 - minh;
183 g[codeindex].g_up = refv - minv;
184 g[codeindex].g_left = refh - minh;
185 g[codeindex].g_bitp =
186 g[codeindex].g_height * ((g[codeindex].g_width + 7) / 8);
187
188 bitp = (glyphs[codeindex] = malloc(g[codeindex].g_bitp)) - 1;
189 if (!glyphs[codeindex])
190 error("out of memory");
191 for (i = minv; i <= maxv; i++) {
192 chp = &charbits[0] + width * i + minh;
193 bitwidth = 0;
194 for (j = minh; j <= maxh; j++, chp++) {
195 if (--bitwidth < 0) {
196 *++bitp = '\0';
197 bitwidth = 7;
198 }
199 if (*chp != '.') *bitp |= 1 << bitwidth;
200 }
201 } /* for i */
202 } /* else */
203 } /* while */
204
205 if (ignorecode) {
206 p.p_last = codeindex - 1;
207 p.p_first = 0;
208 } else {
209 for (i = DIRSIZ - 1; glyphs[i] == (char *) 0; i--);
210 p.p_last = i;
211 for (i = 0; glyphs[i] == (char *) 0; i++);
212 p.p_first = i;
213 }
214 bitwidth = STARTGLYPH + 15 * (1 + p.p_last - p.p_first);
215
216 printf("Rast UCB");
217 wr2(p.p_size); wr1(p.p_version); wr3(STARTGLYPH);
218 wr2(p.p_first); wr2(p.p_last); wr4(p.p_mag);
219 wr4(p.p_desiz); wr4(p.p_linesp); wr4(p.p_wordsp);
220 wr2(p.p_rot); wr1(p.p_cadv); wr1(p.p_ladv);
221 wr4(p.p_id); wr2(p.p_res);
222 for (i = 0; i < STRINGS; i++) putchar('\0');
223
224 for (i = p.p_first; i <= p.p_last; i++) {
225 if (glyphs[i] == (char *) 0) {
226 for (j = 0; j < 15; j++) putchar('\0');
227 } else {
228 wr2(g[i].g_height);
229 wr2(g[i].g_width);
230 wr2(g[i].g_up);
231 wr2(g[i].g_left);
232 wr4(g[i].g_pwidth);
233 wr3(bitwidth);
234 bitwidth += g[i].g_bitp;
235 }
236 } /* for i */
237 fflush(stdout);
238
239 for (i = p.p_first; i <= p.p_last; i++)
240 if (glyphs[i] != (char *) 0)
241 vwrite(glyphs[i], g[i].g_bitp);
242 exit(0);
243 }
244
245
246 /*----------------------------------------------------------------------------*
247 | Routine: vwrite (buffer, buffer_size)
248 |
249 | Results: writes out character array "buffer" of size "buffer_size"
250 | to standard output in small enough chunks that a pipe could
251 | handle them.
252 |
253 | Bugs: this routine shouldn't be needed
254 *----------------------------------------------------------------------------*/
255
vwrite(buf,bufsize)256 vwrite(buf, bufsize)
257 char *buf;
258 int bufsize;
259 {
260 int tsize = 0;
261
262 while (bufsize) {
263 buf += tsize;
264 tsize = bufsize > BUFSIZ ? BUFSIZ : bufsize;
265 if ((tsize = write(1, buf, tsize)) < 0) {
266 perror("ch2rst: write failed");
267 exit(-1);
268 }
269 bufsize -= tsize;
270 }
271 }
272
273
274 /*----------------------------------------------------------------------------*
275 | Routine: error (format_string, argument1, argument2.... )
276 |
277 | Results: fprints a message to standard error, then exits with error
278 | code 1
279 |
280 | Side Efct: This routine does NOT return
281 *----------------------------------------------------------------------------*/
282
283 /*VARARGS1*/
error(string,a1,a2,a3,a4)284 error(string, a1, a2, a3, a4)
285 char *string;
286 {
287 fprintf(stderr, "ch2rst: ");
288 fprintf(stderr, string, a1, a2, a3, a4);
289 fprintf(stderr, "\n");
290 exit(1);
291 }
292
293
294 /*----------------------------------------------------------------------------*
295 | Routine: wr2, wr3, wr4 (and wr1)
296 |
297 | Results: writes out 2, 3, or 4 byte integers in RST byte order, using
298 | the wr1() routine, which writes one byte to standard output.
299 *----------------------------------------------------------------------------*/
300
wr2(i)301 wr2(i)
302 unsigned int i;
303 {
304 wr1((i >> 8) & 255);
305 wr1(i & 255);
306 }
307
wr3(i)308 wr3(i)
309 unsigned int i;
310 {
311 wr1((i >> 16) & 255);
312 wr1(( i >> 8) & 255);
313 wr1(i & 255);
314 }
315
wr4(i)316 wr4(i)
317 unsigned int i;
318 {
319 wr1((i >> 24) & 255);
320 wr1((i >> 16) & 255);
321 wr1((i >> 8) & 255);
322 wr1(i & 255);
323 }
324