diff options
-rw-r--r-- | tools/convbdf.c | 957 |
1 files changed, 957 insertions, 0 deletions
diff --git a/tools/convbdf.c b/tools/convbdf.c new file mode 100644 index 0000000000..c8e5837575 --- /dev/null +++ b/tools/convbdf.c | |||
@@ -0,0 +1,957 @@ | |||
1 | /* | ||
2 | * Convert BDF files to C source and/or Rockbox .fnt file format | ||
3 | * | ||
4 | * Copyright (c) 2002 by Greg Haerr <greg@censoft.com> | ||
5 | * | ||
6 | * What fun it is converting font data... | ||
7 | * | ||
8 | * 09/17/02 Version 1.0 | ||
9 | */ | ||
10 | #include <stdio.h> | ||
11 | #include <stdlib.h> | ||
12 | #include <string.h> | ||
13 | #include <time.h> | ||
14 | |||
15 | /* BEGIN font.h*/ | ||
16 | /* loadable font magic and version #*/ | ||
17 | #define VERSION "RB11" | ||
18 | |||
19 | /* MWIMAGEBITS helper macros*/ | ||
20 | #define MWIMAGE_WORDS(x) (((x)+15)/16) /* image size in words*/ | ||
21 | #define MWIMAGE_BYTES(x) (MWIMAGE_WORDS(x)*sizeof(MWIMAGEBITS)) | ||
22 | #define MWIMAGE_BITSPERIMAGE (sizeof(MWIMAGEBITS) * 8) | ||
23 | #define MWIMAGE_BITVALUE(n) ((MWIMAGEBITS) (((MWIMAGEBITS) 1) << (n))) | ||
24 | #define MWIMAGE_FIRSTBIT (MWIMAGE_BITVALUE(MWIMAGE_BITSPERIMAGE - 1)) | ||
25 | #define MWIMAGE_TESTBIT(m) ((m) & MWIMAGE_FIRSTBIT) | ||
26 | #define MWIMAGE_SHIFTBIT(m) ((MWIMAGEBITS) ((m) << 1)) | ||
27 | |||
28 | typedef unsigned short MWIMAGEBITS; /* bitmap image unit size*/ | ||
29 | |||
30 | /* builtin C-based proportional/fixed font structure */ | ||
31 | /* based on The Microwindows Project http://microwindows.org */ | ||
32 | typedef struct { | ||
33 | char * name; /* font name*/ | ||
34 | int maxwidth; /* max width in pixels*/ | ||
35 | int height; /* height in pixels*/ | ||
36 | int ascent; /* ascent (baseline) height*/ | ||
37 | int firstchar; /* first character in bitmap*/ | ||
38 | int size; /* font size in glyphs*/ | ||
39 | MWIMAGEBITS * bits; /* 16-bit right-padded bitmap data*/ | ||
40 | unsigned long * offset; /* offsets into bitmap data*/ | ||
41 | unsigned char * width; /* character widths or NULL if fixed*/ | ||
42 | int defaultchar; /* default char (not glyph index)*/ | ||
43 | long bits_size; /* # words of MWIMAGEBITS bits*/ | ||
44 | |||
45 | /* unused by runtime system, read in by convbdf*/ | ||
46 | char * facename; /* facename of font*/ | ||
47 | char * copyright; /* copyright info for loadable fonts*/ | ||
48 | int pixel_size; | ||
49 | int descent; | ||
50 | int fbbw, fbbh, fbbx, fbby; | ||
51 | } MWCFONT, *PMWCFONT; | ||
52 | /* END font.h*/ | ||
53 | |||
54 | #define isprefix(buf,str) (!strncmp(buf, str, strlen(str))) | ||
55 | #define strequal(s1,s2) (!strcmp(s1, s2)) | ||
56 | |||
57 | #define EXTRA 300 /* # bytes extra allocation for buggy .bdf files*/ | ||
58 | |||
59 | int gen_c = 0; | ||
60 | int gen_fnt = 0; | ||
61 | int gen_map = 1; | ||
62 | int start_char = 0; | ||
63 | int limit_char = 65535; | ||
64 | int oflag = 0; | ||
65 | char outfile[256]; | ||
66 | |||
67 | void usage(void); | ||
68 | void getopts(int *pac, char ***pav); | ||
69 | int convbdf(char *path); | ||
70 | |||
71 | void free_font(PMWCFONT pf); | ||
72 | PMWCFONT bdf_read_font(char *path); | ||
73 | int bdf_read_header(FILE *fp, PMWCFONT pf); | ||
74 | int bdf_read_bitmaps(FILE *fp, PMWCFONT pf); | ||
75 | char * bdf_getline(FILE *fp, char *buf, int len); | ||
76 | MWIMAGEBITS bdf_hexval(unsigned char *buf, int ndx1, int ndx2); | ||
77 | |||
78 | int gen_c_source(PMWCFONT pf, char *path); | ||
79 | int gen_fnt_file(PMWCFONT pf, char *path); | ||
80 | |||
81 | void | ||
82 | usage(void) | ||
83 | { | ||
84 | char help[] = { | ||
85 | "Usage: convbdf [options] [input-files]\n" | ||
86 | " convbdf [options] [-o output-file] [single-input-file]\n" | ||
87 | "Options:\n" | ||
88 | " -c Convert .bdf to .c source file\n" | ||
89 | " -f Convert .bdf to .fnt font file\n" | ||
90 | " -s N Start output at character encodings >= N\n" | ||
91 | " -l N Limit output to character encodings <= N\n" | ||
92 | " -n Don't generate bitmaps as comments in .c file\n" | ||
93 | }; | ||
94 | |||
95 | fprintf(stderr, help); | ||
96 | } | ||
97 | |||
98 | /* parse command line options*/ | ||
99 | void | ||
100 | getopts(int *pac, char ***pav) | ||
101 | { | ||
102 | char *p; | ||
103 | char **av; | ||
104 | int ac; | ||
105 | |||
106 | ac = *pac; | ||
107 | av = *pav; | ||
108 | while (ac > 0 && av[0][0] == '-') { | ||
109 | p = &av[0][1]; | ||
110 | while( *p) | ||
111 | switch(*p++) { | ||
112 | case ' ': /* multiple -args on av[]*/ | ||
113 | while( *p && *p == ' ') | ||
114 | p++; | ||
115 | if( *p++ != '-') /* next option must have dash*/ | ||
116 | p = ""; | ||
117 | break; /* proceed to next option*/ | ||
118 | case 'c': /* generate .c output*/ | ||
119 | gen_c = 1; | ||
120 | break; | ||
121 | case 'f': /* generate .fnt output*/ | ||
122 | gen_fnt = 1; | ||
123 | break; | ||
124 | case 'n': /* don't gen bitmap comments*/ | ||
125 | gen_map = 0; | ||
126 | break; | ||
127 | case 'o': /* set output file*/ | ||
128 | oflag = 1; | ||
129 | if (*p) { | ||
130 | strcpy(outfile, p); | ||
131 | while (*p && *p != ' ') | ||
132 | p++; | ||
133 | } | ||
134 | else { | ||
135 | av++; ac--; | ||
136 | if (ac > 0) | ||
137 | strcpy(outfile, av[0]); | ||
138 | } | ||
139 | break; | ||
140 | case 'l': /* set encoding limit*/ | ||
141 | if (*p) { | ||
142 | limit_char = atoi(p); | ||
143 | while (*p && *p != ' ') | ||
144 | p++; | ||
145 | } | ||
146 | else { | ||
147 | av++; ac--; | ||
148 | if (ac > 0) | ||
149 | limit_char = atoi(av[0]); | ||
150 | } | ||
151 | break; | ||
152 | case 's': /* set encoding start*/ | ||
153 | if (*p) { | ||
154 | start_char = atoi(p); | ||
155 | while (*p && *p != ' ') | ||
156 | p++; | ||
157 | } | ||
158 | else { | ||
159 | av++; ac--; | ||
160 | if (ac > 0) | ||
161 | start_char = atoi(av[0]); | ||
162 | } | ||
163 | break; | ||
164 | default: | ||
165 | fprintf(stderr, "Unknown option ignored: %c\r\n", *(p-1)); | ||
166 | } | ||
167 | ++av; --ac; | ||
168 | } | ||
169 | *pac = ac; | ||
170 | *pav = av; | ||
171 | } | ||
172 | |||
173 | /* remove directory prefix and file suffix from full path*/ | ||
174 | char * | ||
175 | basename(char *path) | ||
176 | { | ||
177 | char *p, *b; | ||
178 | static char base[256]; | ||
179 | |||
180 | /* remove prepended path and extension*/ | ||
181 | b = path; | ||
182 | for (p=path; *p; ++p) { | ||
183 | if (*p == '/') | ||
184 | b = p + 1; | ||
185 | } | ||
186 | strcpy(base, b); | ||
187 | for (p=base; *p; ++p) { | ||
188 | if (*p == '.') { | ||
189 | *p = 0; | ||
190 | break; | ||
191 | } | ||
192 | } | ||
193 | return base; | ||
194 | } | ||
195 | |||
196 | int | ||
197 | convbdf(char *path) | ||
198 | { | ||
199 | PMWCFONT pf; | ||
200 | int ret = 0; | ||
201 | |||
202 | pf = bdf_read_font(path); | ||
203 | if (!pf) | ||
204 | exit(1); | ||
205 | |||
206 | if (gen_c) { | ||
207 | if (!oflag) { | ||
208 | strcpy(outfile, basename(path)); | ||
209 | strcat(outfile, ".c"); | ||
210 | } | ||
211 | ret |= gen_c_source(pf, outfile); | ||
212 | } | ||
213 | |||
214 | if (gen_fnt) { | ||
215 | if (!oflag) { | ||
216 | strcpy(outfile, basename(path)); | ||
217 | strcat(outfile, ".fnt"); | ||
218 | } | ||
219 | ret |= gen_fnt_file(pf, outfile); | ||
220 | } | ||
221 | |||
222 | free_font(pf); | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | int | ||
227 | main(int ac, char **av) | ||
228 | { | ||
229 | int ret = 0; | ||
230 | |||
231 | ++av; --ac; /* skip av[0]*/ | ||
232 | getopts(&ac, &av); /* read command line options*/ | ||
233 | |||
234 | if (ac < 1 || (!gen_c && !gen_fnt)) { | ||
235 | usage(); | ||
236 | exit(1); | ||
237 | } | ||
238 | if (oflag) { | ||
239 | if (ac > 1 || (gen_c && gen_fnt)) { | ||
240 | usage(); | ||
241 | exit(1); | ||
242 | } | ||
243 | } | ||
244 | |||
245 | while (ac > 0) { | ||
246 | ret |= convbdf(av[0]); | ||
247 | ++av; --ac; | ||
248 | } | ||
249 | |||
250 | exit(ret); | ||
251 | } | ||
252 | |||
253 | /* free font structure*/ | ||
254 | void | ||
255 | free_font(PMWCFONT pf) | ||
256 | { | ||
257 | if (!pf) | ||
258 | return; | ||
259 | if (pf->name) | ||
260 | free(pf->name); | ||
261 | if (pf->facename) | ||
262 | free(pf->facename); | ||
263 | if (pf->bits) | ||
264 | free(pf->bits); | ||
265 | if (pf->offset) | ||
266 | free(pf->offset); | ||
267 | if (pf->width) | ||
268 | free(pf->width); | ||
269 | free(pf); | ||
270 | } | ||
271 | |||
272 | /* build incore structure from .bdf file*/ | ||
273 | PMWCFONT | ||
274 | bdf_read_font(char *path) | ||
275 | { | ||
276 | FILE *fp; | ||
277 | PMWCFONT pf; | ||
278 | |||
279 | fp = fopen(path, "rb"); | ||
280 | if (!fp) { | ||
281 | fprintf(stderr, "Error opening file: %s\n", path); | ||
282 | return NULL; | ||
283 | } | ||
284 | |||
285 | pf = (PMWCFONT)calloc(1, sizeof(MWCFONT)); | ||
286 | if (!pf) | ||
287 | goto errout; | ||
288 | |||
289 | pf->name = strdup(basename(path)); | ||
290 | |||
291 | if (!bdf_read_header(fp, pf)) { | ||
292 | fprintf(stderr, "Error reading font header\n"); | ||
293 | goto errout; | ||
294 | } | ||
295 | |||
296 | if (!bdf_read_bitmaps(fp, pf)) { | ||
297 | fprintf(stderr, "Error reading font bitmaps\n"); | ||
298 | goto errout; | ||
299 | } | ||
300 | |||
301 | fclose(fp); | ||
302 | return pf; | ||
303 | |||
304 | errout: | ||
305 | fclose(fp); | ||
306 | free_font(pf); | ||
307 | return NULL; | ||
308 | } | ||
309 | |||
310 | /* read bdf font header information, return 0 on error*/ | ||
311 | int | ||
312 | bdf_read_header(FILE *fp, PMWCFONT pf) | ||
313 | { | ||
314 | int encoding; | ||
315 | int nchars, maxwidth; | ||
316 | int firstchar = 65535; | ||
317 | int lastchar = -1; | ||
318 | char buf[256]; | ||
319 | char facename[256]; | ||
320 | char copyright[256]; | ||
321 | |||
322 | /* set certain values to errors for later error checking*/ | ||
323 | pf->defaultchar = -1; | ||
324 | pf->ascent = -1; | ||
325 | pf->descent = -1; | ||
326 | |||
327 | for (;;) { | ||
328 | if (!bdf_getline(fp, buf, sizeof(buf))) { | ||
329 | fprintf(stderr, "Error: EOF on file\n"); | ||
330 | return 0; | ||
331 | } | ||
332 | if (isprefix(buf, "FONT ")) { /* not required*/ | ||
333 | if (sscanf(buf, "FONT %[^\n]", facename) != 1) { | ||
334 | fprintf(stderr, "Error: bad 'FONT'\n"); | ||
335 | return 0; | ||
336 | } | ||
337 | pf->facename = strdup(facename); | ||
338 | continue; | ||
339 | } | ||
340 | if (isprefix(buf, "COPYRIGHT ")) { /* not required*/ | ||
341 | if (sscanf(buf, "COPYRIGHT \"%[^\"]", copyright) != 1) { | ||
342 | fprintf(stderr, "Error: bad 'COPYRIGHT'\n"); | ||
343 | return 0; | ||
344 | } | ||
345 | pf->copyright = strdup(copyright); | ||
346 | continue; | ||
347 | } | ||
348 | if (isprefix(buf, "DEFAULT_CHAR ")) { /* not required*/ | ||
349 | if (sscanf(buf, "DEFAULT_CHAR %d", &pf->defaultchar) != 1) { | ||
350 | fprintf(stderr, "Error: bad 'DEFAULT_CHAR'\n"); | ||
351 | return 0; | ||
352 | } | ||
353 | } | ||
354 | if (isprefix(buf, "FONT_DESCENT ")) { | ||
355 | if (sscanf(buf, "FONT_DESCENT %d", &pf->descent) != 1) { | ||
356 | fprintf(stderr, "Error: bad 'FONT_DESCENT'\n"); | ||
357 | return 0; | ||
358 | } | ||
359 | continue; | ||
360 | } | ||
361 | if (isprefix(buf, "FONT_ASCENT ")) { | ||
362 | if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent) != 1) { | ||
363 | fprintf(stderr, "Error: bad 'FONT_ASCENT'\n"); | ||
364 | return 0; | ||
365 | } | ||
366 | continue; | ||
367 | } | ||
368 | if (isprefix(buf, "FONTBOUNDINGBOX ")) { | ||
369 | if (sscanf(buf, "FONTBOUNDINGBOX %d %d %d %d", | ||
370 | &pf->fbbw, &pf->fbbh, &pf->fbbx, &pf->fbby) != 4) { | ||
371 | fprintf(stderr, "Error: bad 'FONTBOUNDINGBOX'\n"); | ||
372 | return 0; | ||
373 | } | ||
374 | continue; | ||
375 | } | ||
376 | if (isprefix(buf, "CHARS ")) { | ||
377 | if (sscanf(buf, "CHARS %d", &nchars) != 1) { | ||
378 | fprintf(stderr, "Error: bad 'CHARS'\n"); | ||
379 | return 0; | ||
380 | } | ||
381 | continue; | ||
382 | } | ||
383 | |||
384 | /* | ||
385 | * Reading ENCODING is necessary to get firstchar/lastchar | ||
386 | * which is needed to pre-calculate our offset and widths | ||
387 | * array sizes. | ||
388 | */ | ||
389 | if (isprefix(buf, "ENCODING ")) { | ||
390 | if (sscanf(buf, "ENCODING %d", &encoding) != 1) { | ||
391 | fprintf(stderr, "Error: bad 'ENCODING'\n"); | ||
392 | return 0; | ||
393 | } | ||
394 | if (encoding >= 0 && encoding <= limit_char && encoding >= start_char) { | ||
395 | if (firstchar > encoding) | ||
396 | firstchar = encoding; | ||
397 | if (lastchar < encoding) | ||
398 | lastchar = encoding; | ||
399 | } | ||
400 | continue; | ||
401 | } | ||
402 | if (strequal(buf, "ENDFONT")) | ||
403 | break; | ||
404 | } | ||
405 | |||
406 | /* calc font height*/ | ||
407 | if (pf->ascent < 0 || pf->descent < 0 || firstchar < 0) { | ||
408 | fprintf(stderr, "Error: Invalid BDF file, requires FONT_ASCENT/FONT_DESCENT/ENCODING\n"); | ||
409 | return 0; | ||
410 | } | ||
411 | pf->height = pf->ascent + pf->descent; | ||
412 | |||
413 | /* calc default char*/ | ||
414 | if (pf->defaultchar < 0 || pf->defaultchar < firstchar) | ||
415 | pf->defaultchar = firstchar; | ||
416 | |||
417 | /* calc font size (offset/width entries)*/ | ||
418 | pf->firstchar = firstchar; | ||
419 | pf->size = lastchar - firstchar + 1; | ||
420 | |||
421 | /* use the font boundingbox to get initial maxwidth*/ | ||
422 | /*maxwidth = pf->fbbw - pf->fbbx;*/ | ||
423 | maxwidth = pf->fbbw; | ||
424 | |||
425 | /* initially use font maxwidth * height for bits allocation*/ | ||
426 | pf->bits_size = nchars * MWIMAGE_WORDS(maxwidth) * pf->height; | ||
427 | |||
428 | /* allocate bits, offset, and width arrays*/ | ||
429 | pf->bits = (MWIMAGEBITS *)malloc(pf->bits_size * sizeof(MWIMAGEBITS) + EXTRA); | ||
430 | pf->offset = (unsigned long *)malloc(pf->size * sizeof(unsigned long)); | ||
431 | pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char)); | ||
432 | |||
433 | if (!pf->bits || !pf->offset || !pf->width) { | ||
434 | fprintf(stderr, "Error: no memory for font load\n"); | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | return 1; | ||
439 | } | ||
440 | |||
441 | /* read bdf font bitmaps, return 0 on error*/ | ||
442 | int | ||
443 | bdf_read_bitmaps(FILE *fp, PMWCFONT pf) | ||
444 | { | ||
445 | long ofs = 0; | ||
446 | int maxwidth = 0; | ||
447 | int i, k, encoding, width; | ||
448 | int bbw, bbh, bbx, bby; | ||
449 | int proportional = 0; | ||
450 | int encodetable = 0; | ||
451 | long l; | ||
452 | char buf[256]; | ||
453 | |||
454 | /* reset file pointer*/ | ||
455 | fseek(fp, 0L, SEEK_SET); | ||
456 | |||
457 | /* initially mark offsets as not used*/ | ||
458 | for (i=0; i<pf->size; ++i) | ||
459 | pf->offset[i] = -1; | ||
460 | |||
461 | for (;;) { | ||
462 | if (!bdf_getline(fp, buf, sizeof(buf))) { | ||
463 | fprintf(stderr, "Error: EOF on file\n"); | ||
464 | return 0; | ||
465 | } | ||
466 | if (isprefix(buf, "STARTCHAR")) { | ||
467 | encoding = width = bbw = bbh = bbx = bby = -1; | ||
468 | continue; | ||
469 | } | ||
470 | if (isprefix(buf, "ENCODING ")) { | ||
471 | if (sscanf(buf, "ENCODING %d", &encoding) != 1) { | ||
472 | fprintf(stderr, "Error: bad 'ENCODING'\n"); | ||
473 | return 0; | ||
474 | } | ||
475 | if (encoding < start_char || encoding > limit_char) | ||
476 | encoding = -1; | ||
477 | continue; | ||
478 | } | ||
479 | if (isprefix(buf, "DWIDTH ")) { | ||
480 | if (sscanf(buf, "DWIDTH %d", &width) != 1) { | ||
481 | fprintf(stderr, "Error: bad 'DWIDTH'\n"); | ||
482 | return 0; | ||
483 | } | ||
484 | /* use font boundingbox width if DWIDTH <= 0*/ | ||
485 | if (width <= 0) | ||
486 | width = pf->fbbw - pf->fbbx; | ||
487 | continue; | ||
488 | } | ||
489 | if (isprefix(buf, "BBX ")) { | ||
490 | if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) { | ||
491 | fprintf(stderr, "Error: bad 'BBX'\n"); | ||
492 | return 0; | ||
493 | } | ||
494 | continue; | ||
495 | } | ||
496 | if (strequal(buf, "BITMAP")) { | ||
497 | MWIMAGEBITS *ch_bitmap = pf->bits + ofs; | ||
498 | int ch_words; | ||
499 | |||
500 | if (encoding < 0) | ||
501 | continue; | ||
502 | |||
503 | /* set bits offset in encode map*/ | ||
504 | if (pf->offset[encoding-pf->firstchar] != (unsigned long)-1) { | ||
505 | fprintf(stderr, "Error: duplicate encoding for character %d (0x%02x), ignoring duplicate\n", | ||
506 | encoding, encoding); | ||
507 | continue; | ||
508 | } | ||
509 | pf->offset[encoding-pf->firstchar] = ofs; | ||
510 | |||
511 | /* calc char width*/ | ||
512 | if (bbx < 0) { | ||
513 | width -= bbx; | ||
514 | /*if (width > maxwidth) | ||
515 | width = maxwidth;*/ | ||
516 | bbx = 0; | ||
517 | } | ||
518 | if (width > maxwidth) | ||
519 | maxwidth = width; | ||
520 | pf->width[encoding-pf->firstchar] = width; | ||
521 | |||
522 | /* clear bitmap*/ | ||
523 | memset(ch_bitmap, 0, MWIMAGE_BYTES(width) * pf->height); | ||
524 | |||
525 | ch_words = MWIMAGE_WORDS(width); | ||
526 | #define BM(row,col) (*(ch_bitmap + ((row)*ch_words) + (col))) | ||
527 | #define MWIMAGE_NIBBLES (MWIMAGE_BITSPERIMAGE/4) | ||
528 | |||
529 | /* read bitmaps*/ | ||
530 | for (i=0; ; ++i) { | ||
531 | int hexnibbles; | ||
532 | |||
533 | if (!bdf_getline(fp, buf, sizeof(buf))) { | ||
534 | fprintf(stderr, "Error: EOF reading BITMAP data\n"); | ||
535 | return 0; | ||
536 | } | ||
537 | if (isprefix(buf, "ENDCHAR")) | ||
538 | break; | ||
539 | |||
540 | hexnibbles = strlen(buf); | ||
541 | for (k=0; k<ch_words; ++k) { | ||
542 | int ndx = k * MWIMAGE_NIBBLES; | ||
543 | int padnibbles = hexnibbles - ndx; | ||
544 | MWIMAGEBITS value; | ||
545 | |||
546 | if (padnibbles <= 0) | ||
547 | break; | ||
548 | if (padnibbles >= MWIMAGE_NIBBLES) | ||
549 | padnibbles = 0; | ||
550 | |||
551 | value = bdf_hexval((unsigned char *)buf, | ||
552 | ndx, ndx+MWIMAGE_NIBBLES-1-padnibbles); | ||
553 | value <<= padnibbles * MWIMAGE_NIBBLES; | ||
554 | |||
555 | BM(pf->height - pf->descent - bby - bbh + i, k) |= | ||
556 | value >> bbx; | ||
557 | /* handle overflow into next image word*/ | ||
558 | if (bbx) { | ||
559 | BM(pf->height - pf->descent - bby - bbh + i, k+1) = | ||
560 | value << (MWIMAGE_BITSPERIMAGE - bbx); | ||
561 | } | ||
562 | } | ||
563 | } | ||
564 | |||
565 | ofs += MWIMAGE_WORDS(width) * pf->height; | ||
566 | |||
567 | continue; | ||
568 | } | ||
569 | if (strequal(buf, "ENDFONT")) | ||
570 | break; | ||
571 | } | ||
572 | |||
573 | /* set max width*/ | ||
574 | pf->maxwidth = maxwidth; | ||
575 | |||
576 | /* change unused offset/width values to default char values*/ | ||
577 | for (i=0; i<pf->size; ++i) { | ||
578 | int defchar = pf->defaultchar - pf->firstchar; | ||
579 | |||
580 | if (pf->offset[i] == (unsigned long)-1) { | ||
581 | pf->offset[i] = pf->offset[defchar]; | ||
582 | pf->width[i] = pf->width[defchar]; | ||
583 | } | ||
584 | } | ||
585 | |||
586 | /* determine whether font doesn't require encode table*/ | ||
587 | l = 0; | ||
588 | for (i=0; i<pf->size; ++i) { | ||
589 | if (pf->offset[i] != l) { | ||
590 | encodetable = 1; | ||
591 | break; | ||
592 | } | ||
593 | l += MWIMAGE_WORDS(pf->width[i]) * pf->height; | ||
594 | } | ||
595 | if (!encodetable) { | ||
596 | free(pf->offset); | ||
597 | pf->offset = NULL; | ||
598 | } | ||
599 | |||
600 | /* determine whether font is fixed-width*/ | ||
601 | for (i=0; i<pf->size; ++i) { | ||
602 | if (pf->width[i] != maxwidth) { | ||
603 | proportional = 1; | ||
604 | break; | ||
605 | } | ||
606 | } | ||
607 | if (!proportional) { | ||
608 | free(pf->width); | ||
609 | pf->width = NULL; | ||
610 | } | ||
611 | |||
612 | /* reallocate bits array to actual bits used*/ | ||
613 | if (ofs < pf->bits_size) { | ||
614 | pf->bits = realloc(pf->bits, ofs * sizeof(MWIMAGEBITS)); | ||
615 | pf->bits_size = ofs; | ||
616 | } else if (ofs > pf->bits_size) { | ||
617 | fprintf(stderr, "Warning: DWIDTH spec > max FONTBOUNDINGBOX\n"); | ||
618 | if (ofs > pf->bits_size+EXTRA) { | ||
619 | fprintf(stderr, "Error: Not enough bits initially allocated\n"); | ||
620 | return 0; | ||
621 | } | ||
622 | pf->bits_size = ofs; | ||
623 | } | ||
624 | |||
625 | return 1; | ||
626 | } | ||
627 | |||
628 | /* read the next non-comment line, returns buf or NULL if EOF*/ | ||
629 | char * | ||
630 | bdf_getline(FILE *fp, char *buf, int len) | ||
631 | { | ||
632 | int c; | ||
633 | char *b; | ||
634 | |||
635 | for (;;) { | ||
636 | b = buf; | ||
637 | while ((c = getc(fp)) != EOF) { | ||
638 | if (c == '\r') | ||
639 | continue; | ||
640 | if (c == '\n') | ||
641 | break; | ||
642 | if (b - buf >= (len - 1)) | ||
643 | break; | ||
644 | *b++ = c; | ||
645 | } | ||
646 | *b = '\0'; | ||
647 | if (c == EOF) | ||
648 | return NULL; | ||
649 | if (b != buf && !isprefix(buf, "COMMENT")) | ||
650 | break; | ||
651 | } | ||
652 | return buf; | ||
653 | } | ||
654 | |||
655 | /* return hex value of portion of buffer*/ | ||
656 | MWIMAGEBITS | ||
657 | bdf_hexval(unsigned char *buf, int ndx1, int ndx2) | ||
658 | { | ||
659 | MWIMAGEBITS val = 0; | ||
660 | int i, c; | ||
661 | |||
662 | for (i=ndx1; i<=ndx2; ++i) { | ||
663 | c = buf[i]; | ||
664 | if (c >= '0' && c <= '9') | ||
665 | c -= '0'; | ||
666 | else if (c >= 'A' && c <= 'F') | ||
667 | c = c - 'A' + 10; | ||
668 | else if (c >= 'a' && c <= 'f') | ||
669 | c = c - 'a' + 10; | ||
670 | else c = 0; | ||
671 | val = (val << 4) | c; | ||
672 | } | ||
673 | return val; | ||
674 | } | ||
675 | |||
676 | /* generate C source from in-core font*/ | ||
677 | int | ||
678 | gen_c_source(PMWCFONT pf, char *path) | ||
679 | { | ||
680 | FILE *ofp; | ||
681 | int i; | ||
682 | int did_defaultchar = 0; | ||
683 | int did_syncmsg = 0; | ||
684 | time_t t = time(0); | ||
685 | MWIMAGEBITS *ofs = pf->bits; | ||
686 | char buf[256]; | ||
687 | char obuf[256]; | ||
688 | char hdr1[] = { | ||
689 | "/* Generated by convbdf on %s. */\n" | ||
690 | "#include \"font.h\"\n" | ||
691 | "\n" | ||
692 | "/* Font information:\n" | ||
693 | " name: %s\n" | ||
694 | " facename: %s\n" | ||
695 | " w x h: %dx%d\n" | ||
696 | " size: %d\n" | ||
697 | " ascent: %d\n" | ||
698 | " descent: %d\n" | ||
699 | " first char: %d (0x%02x)\n" | ||
700 | " last char: %d (0x%02x)\n" | ||
701 | " default char: %d (0x%02x)\n" | ||
702 | " proportional: %s\n" | ||
703 | " %s\n" | ||
704 | "*/\n" | ||
705 | "\n" | ||
706 | "/* Font character bitmap data. */\n" | ||
707 | "static MWIMAGEBITS _%s_bits[] = {\n" | ||
708 | }; | ||
709 | |||
710 | ofp = fopen(path, "w"); | ||
711 | if (!ofp) { | ||
712 | fprintf(stderr, "Can't create %s\n", path); | ||
713 | return 1; | ||
714 | } | ||
715 | fprintf(stderr, "Generating %s\n", path); | ||
716 | |||
717 | strcpy(buf, ctime(&t)); | ||
718 | buf[strlen(buf)-1] = 0; | ||
719 | |||
720 | fprintf(ofp, hdr1, buf, | ||
721 | pf->name, | ||
722 | pf->facename? pf->facename: "", | ||
723 | pf->maxwidth, pf->height, | ||
724 | pf->size, | ||
725 | pf->ascent, pf->descent, | ||
726 | pf->firstchar, pf->firstchar, | ||
727 | pf->firstchar+pf->size-1, pf->firstchar+pf->size-1, | ||
728 | pf->defaultchar, pf->defaultchar, | ||
729 | pf->width? "yes": "no", | ||
730 | pf->copyright? pf->copyright: "", | ||
731 | pf->name); | ||
732 | |||
733 | /* generate bitmaps*/ | ||
734 | for (i=0; i<pf->size; ++i) { | ||
735 | int x; | ||
736 | int bitcount = 0; | ||
737 | int width = pf->width ? pf->width[i] : pf->maxwidth; | ||
738 | int height = pf->height; | ||
739 | MWIMAGEBITS *bits = pf->bits + (pf->offset? pf->offset[i]: (height * i)); | ||
740 | MWIMAGEBITS bitvalue; | ||
741 | |||
742 | /* | ||
743 | * Generate bitmap bits only if not this index isn't | ||
744 | * the default character in encode map, or the default | ||
745 | * character hasn't been generated yet. | ||
746 | */ | ||
747 | if (pf->offset && (pf->offset[i] == pf->offset[pf->defaultchar-pf->firstchar])) { | ||
748 | if (did_defaultchar) | ||
749 | continue; | ||
750 | did_defaultchar = 1; | ||
751 | } | ||
752 | |||
753 | fprintf(ofp, "\n/* Character %d (0x%02x):\n width %d", | ||
754 | i+pf->firstchar, i+pf->firstchar, width); | ||
755 | |||
756 | if (gen_map) { | ||
757 | fprintf(ofp, "\n +"); | ||
758 | for (x=0; x<width; ++x) fprintf(ofp, "-"); | ||
759 | fprintf(ofp, "+\n"); | ||
760 | |||
761 | x = 0; | ||
762 | while (height > 0) { | ||
763 | if (x == 0) fprintf(ofp, " |"); | ||
764 | |||
765 | if (bitcount <= 0) { | ||
766 | bitcount = MWIMAGE_BITSPERIMAGE; | ||
767 | bitvalue = *bits++; | ||
768 | } | ||
769 | |||
770 | fprintf(ofp, MWIMAGE_TESTBIT(bitvalue)? "*": " "); | ||
771 | |||
772 | bitvalue = MWIMAGE_SHIFTBIT(bitvalue); | ||
773 | --bitcount; | ||
774 | if (++x == width) { | ||
775 | fprintf(ofp, "|\n"); | ||
776 | --height; | ||
777 | x = 0; | ||
778 | bitcount = 0; | ||
779 | } | ||
780 | } | ||
781 | fprintf(ofp, " +"); | ||
782 | for (x=0; x<width; ++x) fprintf(ofp, "-"); | ||
783 | fprintf(ofp, "+ */\n"); | ||
784 | } else | ||
785 | fprintf(ofp, " */\n"); | ||
786 | |||
787 | bits = pf->bits + (pf->offset? pf->offset[i]: (pf->height * i)); | ||
788 | for (x=MWIMAGE_WORDS(width)*pf->height; x>0; --x) { | ||
789 | fprintf(ofp, "0x%04x,\n", *bits); | ||
790 | if (!did_syncmsg && *bits++ != *ofs++) { | ||
791 | fprintf(stderr, "Warning: found encoding values in non-sorted order (not an error).\n"); | ||
792 | did_syncmsg = 1; | ||
793 | } | ||
794 | } | ||
795 | } | ||
796 | fprintf(ofp, "};\n\n"); | ||
797 | |||
798 | if (pf->offset) { | ||
799 | /* output offset table*/ | ||
800 | fprintf(ofp, "/* Character->glyph mapping. */\n" | ||
801 | "static unsigned long _%s_offset[] = {\n", | ||
802 | pf->name); | ||
803 | |||
804 | for (i=0; i<pf->size; ++i) | ||
805 | fprintf(ofp, " %ld,\t/* (0x%02x) */\n", pf->offset[i], i+pf->firstchar); | ||
806 | fprintf(ofp, "};\n\n"); | ||
807 | } | ||
808 | |||
809 | /* output width table for proportional fonts*/ | ||
810 | if (pf->width) { | ||
811 | fprintf(ofp, "/* Character width data. */\n" | ||
812 | "static unsigned char _%s_width[] = {\n", | ||
813 | pf->name); | ||
814 | |||
815 | for (i=0; i<pf->size; ++i) | ||
816 | fprintf(ofp, " %d,\t/* (0x%02x) */\n", pf->width[i], i+pf->firstchar); | ||
817 | fprintf(ofp, "};\n\n"); | ||
818 | } | ||
819 | |||
820 | /* output MWCFONT struct*/ | ||
821 | if (pf->offset) | ||
822 | sprintf(obuf, "_%s_offset,", pf->name); | ||
823 | else sprintf(obuf, "0, /* no encode table*/"); | ||
824 | if (pf->width) | ||
825 | sprintf(buf, "_%s_width,", pf->name); | ||
826 | else sprintf(buf, "0, /* fixed width*/"); | ||
827 | fprintf(ofp, "/* Exported structure definition. */\n" | ||
828 | "MWCFONT font_%s = {\n" | ||
829 | " \"%s\",\n" | ||
830 | " %d,\n" | ||
831 | " %d,\n" | ||
832 | " %d,\n" | ||
833 | " %d,\n" | ||
834 | " %d,\n" | ||
835 | " _%s_bits,\n" | ||
836 | " %s\n" | ||
837 | " %s\n" | ||
838 | " %d,\n" | ||
839 | " sizeof(_%s_bits)/sizeof(MWIMAGEBITS),\n" | ||
840 | "};\n", | ||
841 | pf->name, pf->name, | ||
842 | pf->maxwidth, pf->height, | ||
843 | pf->ascent, | ||
844 | pf->firstchar, | ||
845 | pf->size, | ||
846 | pf->name, | ||
847 | obuf, | ||
848 | buf, | ||
849 | pf->defaultchar, | ||
850 | pf->name); | ||
851 | |||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | static int | ||
856 | WRITEBYTE(FILE *fp, unsigned char c) | ||
857 | { | ||
858 | return putc(c, fp) != EOF; | ||
859 | } | ||
860 | |||
861 | static int | ||
862 | WRITESHORT(FILE *fp, unsigned short s) | ||
863 | { | ||
864 | putc(s, fp); | ||
865 | return putc(s>>8, fp) != EOF; | ||
866 | } | ||
867 | |||
868 | static int | ||
869 | WRITELONG(FILE *fp, unsigned long l) | ||
870 | { | ||
871 | putc(l, fp); | ||
872 | putc(l>>8, fp); | ||
873 | putc(l>>16, fp); | ||
874 | return putc(l>>24, fp) != EOF; | ||
875 | } | ||
876 | |||
877 | static int | ||
878 | WRITESTR(FILE *fp, char *str, int count) | ||
879 | { | ||
880 | return fwrite(str, 1, count, fp) == count; | ||
881 | } | ||
882 | |||
883 | static int | ||
884 | WRITESTRPAD(FILE *fp, char *str, int totlen) | ||
885 | { | ||
886 | int ret; | ||
887 | |||
888 | while (str && *str && totlen > 0) | ||
889 | if (*str) { | ||
890 | ret = putc(*str++, fp); | ||
891 | --totlen; | ||
892 | } | ||
893 | while (--totlen >= 0) | ||
894 | ret = putc(' ', fp); | ||
895 | return ret; | ||
896 | } | ||
897 | |||
898 | /* generate .fnt format file from in-core font*/ | ||
899 | int | ||
900 | gen_fnt_file(PMWCFONT pf, char *path) | ||
901 | { | ||
902 | FILE *ofp; | ||
903 | int i; | ||
904 | |||
905 | ofp = fopen(path, "wb"); | ||
906 | if (!ofp) { | ||
907 | fprintf(stderr, "Can't create %s\n", path); | ||
908 | return 1; | ||
909 | } | ||
910 | fprintf(stderr, "Generating %s\n", path); | ||
911 | |||
912 | /* write magic and version #*/ | ||
913 | WRITESTR(ofp, VERSION, 4); | ||
914 | |||
915 | /* internal font name*/ | ||
916 | WRITESTRPAD(ofp, pf->name, 64); | ||
917 | |||
918 | /* copyright*/ | ||
919 | WRITESTRPAD(ofp, pf->copyright, 256); | ||
920 | |||
921 | /* font info*/ | ||
922 | WRITESHORT(ofp, pf->maxwidth); | ||
923 | WRITESHORT(ofp, pf->height); | ||
924 | WRITESHORT(ofp, pf->ascent); | ||
925 | WRITESHORT(ofp, 0); | ||
926 | WRITELONG(ofp, pf->firstchar); | ||
927 | WRITELONG(ofp, pf->defaultchar); | ||
928 | WRITELONG(ofp, pf->size); | ||
929 | |||
930 | /* variable font data sizes*/ | ||
931 | WRITELONG(ofp, pf->bits_size); /* # words of MWIMAGEBITS*/ | ||
932 | WRITELONG(ofp, pf->offset? pf->size: 0); /* # longs of offset*/ | ||
933 | WRITELONG(ofp, pf->width? pf->size: 0); /* # bytes of width*/ | ||
934 | |||
935 | /* variable font data*/ | ||
936 | for (i=0; i<pf->bits_size; ++i) | ||
937 | WRITESHORT(ofp, pf->bits[i]); | ||
938 | if (ftell(ofp) & 2) | ||
939 | WRITESHORT(ofp, 0); /* pad to 32-bit boundary*/ | ||
940 | |||
941 | if (pf->offset) | ||
942 | for (i=0; i<pf->size; ++i) | ||
943 | WRITELONG(ofp, pf->offset[i]); | ||
944 | |||
945 | if (pf->width) | ||
946 | for (i=0; i<pf->size; ++i) | ||
947 | WRITEBYTE(ofp, pf->width[i]); | ||
948 | |||
949 | fclose(ofp); | ||
950 | return 0; | ||
951 | } | ||
952 | |||
953 | /* ----------------------------------------------------------------- | ||
954 | * local variables: | ||
955 | * eval: (load-file "../firmware/rockbox-mode.el") | ||
956 | * end: | ||
957 | */ | ||