Provide better stats (print the total number of glyphs as well)
[kugel-rb/myfork.git] / tools / convbdf.c
blobb566d2cd2eba89025bb16afb611d94553deeff28
1 /*
2 * Convert BDF files to C source and/or Rockbox .fnt file format
4 * Copyright (c) 2002 by Greg Haerr <greg@censoft.com>
6 * What fun it is converting font data...
8 * 09/17/02 Version 1.0
9 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <time.h>
15 #define ROTATE /* define this for the new, rotated format */
17 /* BEGIN font.h*/
18 /* loadable font magic and version #*/
19 #ifdef ROTATE
20 #define VERSION "RB12" /* newer version */
21 #else
22 #define VERSION "RB11"
23 #endif
25 /* bitmap_t helper macros*/
26 #define BITMAP_WORDS(x) (((x)+15)/16) /* image size in words*/
27 #define BITMAP_BYTES(x) (BITMAP_WORDS(x)*sizeof(bitmap_t))
28 #define BITMAP_BITSPERIMAGE (sizeof(bitmap_t) * 8)
29 #define BITMAP_BITVALUE(n) ((bitmap_t) (((bitmap_t) 1) << (n)))
30 #define BITMAP_FIRSTBIT (BITMAP_BITVALUE(BITMAP_BITSPERIMAGE - 1))
31 #define BITMAP_TESTBIT(m) ((m) & BITMAP_FIRSTBIT)
32 #define BITMAP_SHIFTBIT(m) ((bitmap_t) ((m) << 1))
34 typedef unsigned short bitmap_t; /* bitmap image unit size*/
36 /* builtin C-based proportional/fixed font structure */
37 /* based on The Microwindows Project http://microwindows.org */
38 struct font {
39 int maxwidth; /* max width in pixels*/
40 int height; /* height in pixels*/
41 int ascent; /* ascent (baseline) height*/
42 int firstchar; /* first character in bitmap*/
43 int size; /* font size in glyphs ('holes' included) */
44 bitmap_t* bits; /* 16-bit right-padded bitmap data*/
45 unsigned int* offset; /* offsets into bitmap data*/
46 unsigned char* width; /* character widths or NULL if fixed*/
47 int defaultchar; /* default char (not glyph index)*/
48 int bits_size; /* # words of bitmap_t bits*/
50 /* unused by runtime system, read in by convbdf */
51 unsigned int nchars; /* number of different glyphs */
52 unsigned int* offrot; /* offsets into rotated bitmap data*/
53 char * name; /* font name*/
54 char * facename; /* facename of font*/
55 char * copyright; /* copyright info for loadable fonts*/
56 int pixel_size;
57 int descent;
58 int fbbw, fbbh, fbbx, fbby;
60 /* Max 'overflow' of a char's ascent (descent) over the font's one */
61 int max_over_ascent, max_over_descent;
63 /* The number of clipped ascents/descents/total */
64 int num_clipped_ascent, num_clipped_descent, num_clipped;
66 /* END font.h*/
68 #define isprefix(buf,str) (!strncmp(buf, str, strlen(str)))
69 #define strequal(s1,s2) (!strcmp(s1, s2))
71 #define MAX(a,b) ((a) > (b) ? (a) : (b))
72 #define MIN(a,b) ((a) < (b) ? (a) : (b))
74 #define EXTRA 300 /* # bytes extra allocation for buggy .bdf files*/
76 int gen_c = 0;
77 int gen_h = 0;
78 int gen_fnt = 0;
79 int gen_map = 1;
80 int start_char = 0;
81 int limit_char = 65535;
82 int oflag = 0;
83 char outfile[256];
85 void usage(void);
86 void getopts(int *pac, char ***pav);
87 int convbdf(char *path);
89 void free_font(struct font* pf);
90 struct font* bdf_read_font(char *path);
91 int bdf_read_header(FILE *fp, struct font* pf);
92 int bdf_read_bitmaps(FILE *fp, struct font* pf);
93 char * bdf_getline(FILE *fp, char *buf, int len);
94 bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2);
96 int gen_c_source(struct font* pf, char *path);
97 int gen_h_header(struct font* pf, char *path);
98 int gen_fnt_file(struct font* pf, char *path);
100 void
101 usage(void)
103 char help[] = {
104 "Usage: convbdf [options] [input-files]\n"
105 " convbdf [options] [-o output-file] [single-input-file]\n"
106 "Options:\n"
107 " -c Convert .bdf to .c source file\n"
108 " -h Convert .bdf to .h header file (to create sysfont.h)\n"
109 " -f Convert .bdf to .fnt font file\n"
110 " -s N Start output at character encodings >= N\n"
111 " -l N Limit output to character encodings <= N\n"
112 " -n Don't generate bitmaps as comments in .c file\n"
115 fprintf(stderr, "%s", help);
118 /* parse command line options*/
119 void getopts(int *pac, char ***pav)
121 char *p;
122 char **av;
123 int ac;
125 ac = *pac;
126 av = *pav;
127 while (ac > 0 && av[0][0] == '-') {
128 p = &av[0][1];
129 while( *p)
130 switch(*p++) {
131 case ' ': /* multiple -args on av[]*/
132 while( *p && *p == ' ')
133 p++;
134 if( *p++ != '-') /* next option must have dash*/
135 p = "";
136 break; /* proceed to next option*/
137 case 'c': /* generate .c output*/
138 gen_c = 1;
139 break;
140 case 'h': /* generate .h output*/
141 gen_h = 1;
142 break;
143 case 'f': /* generate .fnt output*/
144 gen_fnt = 1;
145 break;
146 case 'n': /* don't gen bitmap comments*/
147 gen_map = 0;
148 break;
149 case 'o': /* set output file*/
150 oflag = 1;
151 if (*p) {
152 strcpy(outfile, p);
153 while (*p && *p != ' ')
154 p++;
156 else {
157 av++; ac--;
158 if (ac > 0)
159 strcpy(outfile, av[0]);
161 break;
162 case 'l': /* set encoding limit*/
163 if (*p) {
164 limit_char = atoi(p);
165 while (*p && *p != ' ')
166 p++;
168 else {
169 av++; ac--;
170 if (ac > 0)
171 limit_char = atoi(av[0]);
173 break;
174 case 's': /* set encoding start*/
175 if (*p) {
176 start_char = atoi(p);
177 while (*p && *p != ' ')
178 p++;
180 else {
181 av++; ac--;
182 if (ac > 0)
183 start_char = atoi(av[0]);
185 break;
186 default:
187 fprintf(stderr, "Unknown option ignored: %c\r\n", *(p-1));
189 ++av; --ac;
191 *pac = ac;
192 *pav = av;
195 /* remove directory prefix and file suffix from full path*/
196 char *basename(char *path)
198 char *p, *b;
199 static char base[256];
201 /* remove prepended path and extension*/
202 b = path;
203 for (p=path; *p; ++p) {
204 if (*p == '/')
205 b = p + 1;
207 strcpy(base, b);
208 for (p=base; *p; ++p) {
209 if (*p == '.') {
210 *p = 0;
211 break;
214 return base;
217 int convbdf(char *path)
219 struct font* pf;
220 int ret = 0;
222 pf = bdf_read_font(path);
223 if (!pf)
224 exit(1);
226 if (gen_c) {
227 if (!oflag) {
228 strcpy(outfile, basename(path));
229 strcat(outfile, ".c");
231 ret |= gen_c_source(pf, outfile);
234 if (gen_h) {
235 if (!oflag) {
236 strcpy(outfile, basename(path));
237 strcat(outfile, ".h");
239 ret |= gen_h_header(pf, outfile);
242 if (gen_fnt) {
243 if (!oflag) {
244 strcpy(outfile, basename(path));
245 strcat(outfile, ".fnt");
247 ret |= gen_fnt_file(pf, outfile);
250 free_font(pf);
251 return ret;
254 int main(int ac, char **av)
256 int ret = 0;
258 ++av; --ac; /* skip av[0]*/
259 getopts(&ac, &av); /* read command line options*/
261 if (ac < 1 || (!gen_c && !gen_h && !gen_fnt)) {
262 usage();
263 exit(1);
265 if (oflag) {
266 if (ac > 1 || (gen_c && gen_fnt) || (gen_c && gen_h) || (gen_h && gen_fnt)) {
267 usage();
268 exit(1);
272 while (ac > 0) {
273 ret |= convbdf(av[0]);
274 ++av; --ac;
277 exit(ret);
280 /* free font structure*/
281 void free_font(struct font* pf)
283 if (!pf)
284 return;
285 if (pf->name)
286 free(pf->name);
287 if (pf->facename)
288 free(pf->facename);
289 if (pf->bits)
290 free(pf->bits);
291 if (pf->offset)
292 free(pf->offset);
293 if (pf->offrot)
294 free(pf->offrot);
295 if (pf->width)
296 free(pf->width);
297 free(pf);
300 /* build incore structure from .bdf file*/
301 struct font* bdf_read_font(char *path)
303 FILE *fp;
304 struct font* pf;
306 fp = fopen(path, "rb");
307 if (!fp) {
308 fprintf(stderr, "Error opening file: %s\n", path);
309 return NULL;
312 pf = (struct font*)calloc(1, sizeof(struct font));
313 if (!pf)
314 goto errout;
316 pf->name = strdup(basename(path));
318 if (!bdf_read_header(fp, pf)) {
319 fprintf(stderr, "Error reading font header\n");
320 goto errout;
323 pf->max_over_ascent = pf->max_over_descent = 0;
324 pf->num_clipped_ascent = pf->num_clipped_descent = pf->num_clipped = 0;
326 if (!bdf_read_bitmaps(fp, pf)) {
327 fprintf(stderr, "Error reading font bitmaps\n");
328 goto errout;
331 if (pf->num_clipped > 0) {
332 fprintf(stderr, "Warning: %d characters out of %u were clipped "
333 "(%d at ascent, %d at descent)\n",
334 pf->num_clipped, pf->nchars,
335 pf->num_clipped_ascent, pf->num_clipped_descent);
336 fprintf(stderr, " max overflows: ascent: %d, descent: %d\n",
337 pf->max_over_ascent, pf->max_over_descent);
340 fclose(fp);
341 return pf;
343 errout:
344 fclose(fp);
345 free_font(pf);
346 return NULL;
349 /* read bdf font header information, return 0 on error*/
350 int bdf_read_header(FILE *fp, struct font* pf)
352 int encoding;
353 int maxwidth;
354 int firstchar = 65535;
355 int lastchar = -1;
356 char buf[256];
357 char facename[256];
358 char copyright[256];
360 /* set certain values to errors for later error checking*/
361 pf->defaultchar = -1;
362 pf->ascent = -1;
363 pf->descent = -1;
365 for (;;) {
366 if (!bdf_getline(fp, buf, sizeof(buf))) {
367 fprintf(stderr, "Error: EOF on file\n");
368 return 0;
370 if (isprefix(buf, "FONT ")) { /* not required*/
371 if (sscanf(buf, "FONT %[^\n]", facename) != 1) {
372 fprintf(stderr, "Error: bad 'FONT'\n");
373 return 0;
375 pf->facename = strdup(facename);
376 continue;
378 if (isprefix(buf, "COPYRIGHT ")) { /* not required*/
379 if (sscanf(buf, "COPYRIGHT \"%[^\"]", copyright) != 1) {
380 fprintf(stderr, "Error: bad 'COPYRIGHT'\n");
381 return 0;
383 pf->copyright = strdup(copyright);
384 continue;
386 if (isprefix(buf, "DEFAULT_CHAR ")) { /* not required*/
387 if (sscanf(buf, "DEFAULT_CHAR %d", &pf->defaultchar) != 1) {
388 fprintf(stderr, "Error: bad 'DEFAULT_CHAR'\n");
389 return 0;
392 if (isprefix(buf, "FONT_DESCENT ")) {
393 if (sscanf(buf, "FONT_DESCENT %d", &pf->descent) != 1) {
394 fprintf(stderr, "Error: bad 'FONT_DESCENT'\n");
395 return 0;
397 continue;
399 if (isprefix(buf, "FONT_ASCENT ")) {
400 if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent) != 1) {
401 fprintf(stderr, "Error: bad 'FONT_ASCENT'\n");
402 return 0;
404 continue;
406 if (isprefix(buf, "FONTBOUNDINGBOX ")) {
407 if (sscanf(buf, "FONTBOUNDINGBOX %d %d %d %d",
408 &pf->fbbw, &pf->fbbh, &pf->fbbx, &pf->fbby) != 4) {
409 fprintf(stderr, "Error: bad 'FONTBOUNDINGBOX'\n");
410 return 0;
412 continue;
414 if (isprefix(buf, "CHARS ")) {
415 if (sscanf(buf, "CHARS %u", &pf->nchars) != 1) {
416 fprintf(stderr, "Error: bad 'CHARS'\n");
417 return 0;
419 continue;
423 * Reading ENCODING is necessary to get firstchar/lastchar
424 * which is needed to pre-calculate our offset and widths
425 * array sizes.
427 if (isprefix(buf, "ENCODING ")) {
428 if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
429 fprintf(stderr, "Error: bad 'ENCODING'\n");
430 return 0;
432 if (encoding >= 0 &&
433 encoding <= limit_char &&
434 encoding >= start_char) {
436 if (firstchar > encoding)
437 firstchar = encoding;
438 if (lastchar < encoding)
439 lastchar = encoding;
441 continue;
443 if (strequal(buf, "ENDFONT"))
444 break;
447 /* calc font height*/
448 if (pf->ascent < 0 || pf->descent < 0 || firstchar < 0) {
449 fprintf(stderr, "Error: Invalid BDF file, requires FONT_ASCENT/FONT_DESCENT/ENCODING\n");
450 return 0;
452 pf->height = pf->ascent + pf->descent;
454 /* calc default char*/
455 if (pf->defaultchar < 0 ||
456 pf->defaultchar < firstchar ||
457 pf->defaultchar > limit_char ||
458 pf->defaultchar > lastchar)
459 pf->defaultchar = firstchar;
461 /* calc font size (offset/width entries)*/
462 pf->firstchar = firstchar;
463 pf->size = lastchar - firstchar + 1;
465 /* use the font boundingbox to get initial maxwidth*/
466 /*maxwidth = pf->fbbw - pf->fbbx;*/
467 maxwidth = pf->fbbw;
469 /* initially use font maxwidth * height for bits allocation*/
470 pf->bits_size = pf->nchars * BITMAP_WORDS(maxwidth) * pf->height;
472 /* allocate bits, offset, and width arrays*/
473 pf->bits = (bitmap_t *)malloc(pf->bits_size * sizeof(bitmap_t) + EXTRA);
474 pf->offset = (unsigned int *)malloc(pf->size * sizeof(unsigned int));
475 pf->offrot = (unsigned int *)malloc(pf->size * sizeof(unsigned int));
476 pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char));
478 if (!pf->bits || !pf->offset || !pf->offrot || !pf->width) {
479 fprintf(stderr, "Error: no memory for font load\n");
480 return 0;
483 return 1;
486 /* read bdf font bitmaps, return 0 on error*/
487 int bdf_read_bitmaps(FILE *fp, struct font* pf)
489 int ofs = 0;
490 int ofr = 0;
491 int maxwidth = 0;
492 int i, k, encoding, width;
493 int bbw, bbh, bbx, bby;
494 int proportional = 0;
495 int encodetable = 0;
496 int l;
497 char buf[256];
499 /* reset file pointer*/
500 fseek(fp, 0L, SEEK_SET);
502 /* initially mark offsets as not used*/
503 for (i=0; i<pf->size; ++i)
504 pf->offset[i] = -1;
506 for (;;) {
507 if (!bdf_getline(fp, buf, sizeof(buf))) {
508 fprintf(stderr, "Error: EOF on file\n");
509 return 0;
511 if (isprefix(buf, "STARTCHAR")) {
512 encoding = width = -1;
513 bbw = pf->fbbw;
514 bbh = pf->fbbh;
515 bbx = pf->fbbx;
516 bby = pf->fbby;
517 continue;
519 if (isprefix(buf, "ENCODING ")) {
520 if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
521 fprintf(stderr, "Error: bad 'ENCODING'\n");
522 return 0;
524 if (encoding < start_char || encoding > limit_char)
525 encoding = -1;
526 continue;
528 if (isprefix(buf, "DWIDTH ")) {
529 if (sscanf(buf, "DWIDTH %d", &width) != 1) {
530 fprintf(stderr, "Error: bad 'DWIDTH'\n");
531 return 0;
533 /* use font boundingbox width if DWIDTH <= 0*/
534 if (width <= 0)
535 width = pf->fbbw - pf->fbbx;
536 continue;
538 if (isprefix(buf, "BBX ")) {
539 if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) {
540 fprintf(stderr, "Error: bad 'BBX'\n");
541 return 0;
543 continue;
545 if (strequal(buf, "BITMAP") || strequal(buf, "BITMAP ")) {
546 bitmap_t *ch_bitmap = pf->bits + ofs;
547 int ch_words;
548 int overflow_asc, overflow_desc;
549 int bbh_orig, bby_orig, y;
551 if (encoding < 0)
552 continue;
554 /* set bits offset in encode map*/
555 if (pf->offset[encoding-pf->firstchar] != (unsigned int)-1) {
556 fprintf(stderr, "Error: duplicate encoding for character %d (0x%02x), ignoring duplicate\n",
557 encoding, encoding);
558 continue;
560 pf->offset[encoding-pf->firstchar] = ofs;
561 pf->offrot[encoding-pf->firstchar] = ofr;
563 /* calc char width*/
564 if (bbx < 0) {
565 width -= bbx;
566 /*if (width > maxwidth)
567 width = maxwidth;*/
568 bbx = 0;
570 if (width > maxwidth)
571 maxwidth = width;
572 pf->width[encoding-pf->firstchar] = width;
574 /* clear bitmap*/
575 memset(ch_bitmap, 0, BITMAP_BYTES(width) * pf->height);
577 ch_words = BITMAP_WORDS(width);
578 #define BM(row,col) (*(ch_bitmap + ((row)*ch_words) + (col)))
579 #define BITMAP_NIBBLES (BITMAP_BITSPERIMAGE/4)
581 bbh_orig = bbh;
582 bby_orig = bby;
584 overflow_asc = bby + bbh - pf->ascent;
585 if (overflow_asc > 0) {
586 pf->num_clipped_ascent++;
587 if (overflow_asc > pf->max_over_ascent) {
588 pf->max_over_ascent = overflow_asc;
590 bbh = MAX(bbh - overflow_asc, 0); /* Clipped -> decrease the height */
591 fprintf(stderr, "Warning: character %d goes %d pixel(s)"
592 " beyond the font's ascent, it will be clipped\n",
593 encoding, overflow_asc);
595 overflow_desc = -bby - pf->descent;
596 if (overflow_desc > 0) {
597 pf->num_clipped_descent++;
598 if (overflow_desc > pf->max_over_descent) {
599 pf->max_over_descent = overflow_desc;
601 bby += overflow_desc;
602 bbh = MAX(bbh - overflow_desc, 0); /* Clipped -> decrease the height */
603 fprintf(stderr, "Warning: character %d goes %d pixel(s)"
604 " beyond the font's descent, it will be clipped\n",
605 encoding, overflow_desc);
607 if (overflow_asc > 0 || overflow_desc > 0) {
608 pf->num_clipped++;
611 y = bby_orig + bbh_orig; /* 0-based y within the char */
613 /* read bitmaps*/
614 for (i=0; ; ++i) {
615 int hexnibbles;
617 if (!bdf_getline(fp, buf, sizeof(buf))) {
618 fprintf(stderr, "Error: EOF reading BITMAP data\n");
619 return 0;
621 if (isprefix(buf, "ENDCHAR"))
622 break;
624 y--;
625 if ((y >= pf->ascent) || (y < -pf->descent)) {
626 /* We're beyond the area that Rockbox can render -> clip */
627 --i; /* This line doesn't count */
628 continue;
631 hexnibbles = strlen(buf);
632 for (k=0; k<ch_words; ++k) {
633 int ndx = k * BITMAP_NIBBLES;
634 int padnibbles = hexnibbles - ndx;
635 bitmap_t value;
637 if (padnibbles <= 0)
638 break;
639 if (padnibbles >= (int)BITMAP_NIBBLES)
640 padnibbles = 0;
642 value = bdf_hexval((unsigned char *)buf,
643 ndx, ndx+BITMAP_NIBBLES-1-padnibbles);
644 value <<= padnibbles * BITMAP_NIBBLES;
646 BM(pf->height - pf->descent - bby - bbh + i, k) |=
647 value >> bbx;
648 /* handle overflow into next image word*/
649 if (bbx) {
650 BM(pf->height - pf->descent - bby - bbh + i, k+1) =
651 value << (BITMAP_BITSPERIMAGE - bbx);
656 ofs += BITMAP_WORDS(width) * pf->height;
657 ofr += pf->width[encoding-pf->firstchar] * ((pf->height+7)/8);
659 continue;
661 if (strequal(buf, "ENDFONT"))
662 break;
665 /* set max width*/
666 pf->maxwidth = maxwidth;
668 /* change unused width values to default char values*/
669 for (i=0; i<pf->size; ++i) {
670 int defchar = pf->defaultchar - pf->firstchar;
672 if (pf->offset[i] == (unsigned int)-1)
673 pf->width[i] = pf->width[defchar];
676 /* determine whether font doesn't require encode table*/
677 #ifdef ROTATE
678 l = 0;
679 for (i=0; i<pf->size; ++i) {
680 if ((int)pf->offrot[i] != l) {
681 encodetable = 1;
682 break;
684 l += pf->maxwidth * ((pf->height + 7) / 8);
686 #else
687 l = 0;
688 for (i=0; i<pf->size; ++i) {
689 if (pf->offset[i] != l) {
690 encodetable = 1;
691 break;
693 l += BITMAP_WORDS(pf->width[i]) * pf->height;
695 #endif
696 if (!encodetable) {
697 free(pf->offset);
698 pf->offset = NULL;
701 /* determine whether font is fixed-width*/
702 for (i=0; i<pf->size; ++i) {
703 if (pf->width[i] != maxwidth) {
704 proportional = 1;
705 break;
708 if (!proportional) {
709 free(pf->width);
710 pf->width = NULL;
713 /* reallocate bits array to actual bits used*/
714 if (ofs < pf->bits_size) {
715 pf->bits = realloc(pf->bits, ofs * sizeof(bitmap_t));
716 pf->bits_size = ofs;
718 else {
719 if (ofs > pf->bits_size) {
720 fprintf(stderr, "Warning: DWIDTH spec > max FONTBOUNDINGBOX\n");
721 if (ofs > pf->bits_size+EXTRA) {
722 fprintf(stderr, "Error: Not enough bits initially allocated\n");
723 return 0;
725 pf->bits_size = ofs;
729 #ifdef ROTATE
730 pf->bits_size = ofr; /* always update, rotated is smaller */
731 #endif
733 return 1;
736 /* read the next non-comment line, returns buf or NULL if EOF*/
737 char *bdf_getline(FILE *fp, char *buf, int len)
739 int c;
740 char *b;
742 for (;;) {
743 b = buf;
744 while ((c = getc(fp)) != EOF) {
745 if (c == '\r')
746 continue;
747 if (c == '\n')
748 break;
749 if (b - buf >= (len - 1))
750 break;
751 *b++ = c;
753 *b = '\0';
754 if (c == EOF && b == buf)
755 return NULL;
756 if (b != buf && !isprefix(buf, "COMMENT"))
757 break;
759 return buf;
762 /* return hex value of portion of buffer*/
763 bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2)
765 bitmap_t val = 0;
766 int i, c;
768 for (i=ndx1; i<=ndx2; ++i) {
769 c = buf[i];
770 if (c >= '0' && c <= '9')
771 c -= '0';
772 else
773 if (c >= 'A' && c <= 'F')
774 c = c - 'A' + 10;
775 else
776 if (c >= 'a' && c <= 'f')
777 c = c - 'a' + 10;
778 else
779 c = 0;
780 val = (val << 4) | c;
782 return val;
786 * Take an bitmap_t bitmap and convert to Rockbox format.
787 * Used for converting font glyphs for the time being.
788 * Can use for standard X11 and Win32 images as well.
789 * See format description in lcd-recorder.c
791 * Doing it this way keeps fonts in standard formats,
792 * as well as keeping Rockbox hw bitmap format.
794 int rotleft(unsigned char *dst, /* output buffer */
795 size_t dstlen, /* buffer size */
796 bitmap_t *src, unsigned int width, unsigned int height)
798 unsigned int i,j;
799 unsigned int src_words; /* # words of input image*/
800 unsigned int dst_mask; /* bit mask for destination */
801 bitmap_t src_mask; /* bit mask for source */
803 /* calc words of input image*/
804 src_words = BITMAP_WORDS(width) * height;
806 if(((height + 7) / 8) * width > dstlen) {
807 fprintf(stderr, "%s:%d %d x %d overflows %ld bytes buffer, needs %d\n",
808 __FILE__, __LINE__, width, height, (unsigned long)dstlen,
809 ((height + 7) / 8) * width );
810 return 0;
813 /* clear background*/
814 memset(dst, 0, ((height + 7) / 8) * width);
816 dst_mask = 1;
818 for (i=0; i < src_words; i++) {
820 /* calc src input bit*/
821 src_mask = 1 << (sizeof (bitmap_t) * 8 - 1);
823 /* for each input column...*/
824 for(j=0; j < width; j++) {
826 if (src_mask == 0) /* input word done? */
828 src_mask = 1 << (sizeof (bitmap_t) * 8 - 1);
829 i++; /* next input word */
832 /* if set in input, set in rotated output */
833 if (src[i] & src_mask)
834 dst[j] |= dst_mask;
836 src_mask >>= 1; /* next input bit */
839 dst_mask <<= 1; /* next output bit (row) */
840 if (dst_mask > (1 << 7)) /* output bit > 7? */
842 dst_mask = 1;
843 dst += width; /* next output byte row */
846 return ((height + 7) / 8) * width; /* return result size in bytes */
850 /* generate C source from in-core font*/
851 int gen_c_source(struct font* pf, char *path)
853 FILE *ofp;
854 int i, ofr = 0;
855 time_t t = time(0);
856 #ifndef ROTATE
857 int did_syncmsg = 0;
858 bitmap_t *ofs = pf->bits;
859 #endif
860 char buf[256];
861 char obuf[256];
862 char hdr1[] = {
863 "/* Generated by convbdf on %s. */\n"
864 "#include \"font.h\"\n"
865 "#ifdef HAVE_LCD_BITMAP\n"
866 "\n"
867 "/* Font information:\n"
868 " name: %s\n"
869 " facename: %s\n"
870 " w x h: %dx%d\n"
871 " size: %d\n"
872 " ascent: %d\n"
873 " descent: %d\n"
874 " first char: %d (0x%02x)\n"
875 " last char: %d (0x%02x)\n"
876 " default char: %d (0x%02x)\n"
877 " proportional: %s\n"
878 " %s\n"
879 "*/\n"
880 "\n"
881 "/* Font character bitmap data. */\n"
882 "static const unsigned char _font_bits[] = {\n"
885 ofp = fopen(path, "w");
886 if (!ofp) {
887 fprintf(stderr, "Can't create %s\n", path);
888 return 1;
891 strcpy(buf, ctime(&t));
892 buf[strlen(buf)-1] = 0;
894 fprintf(ofp, hdr1, buf,
895 pf->name,
896 pf->facename? pf->facename: "",
897 pf->maxwidth, pf->height,
898 pf->size,
899 pf->ascent, pf->descent,
900 pf->firstchar, pf->firstchar,
901 pf->firstchar+pf->size-1, pf->firstchar+pf->size-1,
902 pf->defaultchar, pf->defaultchar,
903 pf->width? "yes": "no",
904 pf->copyright? pf->copyright: "");
906 /* generate bitmaps*/
907 for (i=0; i<pf->size; ++i) {
908 int x;
909 int bitcount = 0;
910 int width = pf->width ? pf->width[i] : pf->maxwidth;
911 int height = pf->height;
912 bitmap_t *bits;
913 bitmap_t bitvalue=0;
915 /* Skip missing glyphs */
916 if (pf->offset && (pf->offset[i] == (unsigned int)-1))
917 continue;
919 bits = pf->bits + (pf->offset? (int)pf->offset[i]: (pf->height * i));
921 fprintf(ofp, "\n/* Character %d (0x%02x):\n width %d",
922 i+pf->firstchar, i+pf->firstchar, width);
924 if (gen_map) {
925 fprintf(ofp, "\n +");
926 for (x=0; x<width; ++x) fprintf(ofp, "-");
927 fprintf(ofp, "+\n");
929 x = 0;
930 while (height > 0) {
931 if (x == 0) fprintf(ofp, " |");
933 if (bitcount <= 0) {
934 bitcount = BITMAP_BITSPERIMAGE;
935 bitvalue = *bits++;
938 fprintf(ofp, BITMAP_TESTBIT(bitvalue)? "*": " ");
940 bitvalue = BITMAP_SHIFTBIT(bitvalue);
941 --bitcount;
942 if (++x == width) {
943 fprintf(ofp, "|\n");
944 --height;
945 x = 0;
946 bitcount = 0;
949 fprintf(ofp, " +");
950 for (x=0; x<width; ++x)
951 fprintf(ofp, "-");
952 fprintf(ofp, "+ */\n");
954 else
955 fprintf(ofp, " */\n");
957 bits = pf->bits + (pf->offset? (int)pf->offset[i]: (pf->height * i));
958 #ifdef ROTATE /* pre-rotated into Rockbox bitmap format */
960 unsigned char bytemap[512];
961 int y8, ix=0;
963 int size = rotleft(bytemap, sizeof(bytemap), bits, width,
964 pf->height);
965 for (y8=0; y8<pf->height; y8+=8) /* column rows */
967 for (x=0; x<width; x++) {
968 fprintf(ofp, "0x%02x, ", bytemap[ix]);
969 ix++;
971 fprintf(ofp, "\n");
974 /* update offrot since bits are now in sorted order */
975 pf->offrot[i] = ofr;
976 ofr += size;
979 #else
980 for (x=BITMAP_WORDS(width)*pf->height; x>0; --x) {
981 fprintf(ofp, "0x%04x,\n", *bits);
982 if (!did_syncmsg && *bits++ != *ofs++) {
983 fprintf(stderr, "Warning: found encoding values in non-sorted order (not an error).\n");
984 did_syncmsg = 1;
987 #endif
989 fprintf(ofp, "};\n\n");
991 if (pf->offset) {
992 /* output offset table*/
993 fprintf(ofp, "/* Character->glyph mapping. */\n"
994 "static const unsigned short _sysfont_offset[] = {\n");
996 for (i=0; i<pf->size; ++i) {
997 if (pf->offset[i] == (unsigned int)-1) {
998 pf->offset[i] = pf->offset[pf->defaultchar - pf->firstchar];
999 pf->offrot[i] = pf->offrot[pf->defaultchar - pf->firstchar];
1001 fprintf(ofp, " %d,\t/* (0x%02x) */\n",
1002 #ifdef ROTATE
1003 pf->offrot[i], i+pf->firstchar);
1004 #else
1005 pf->offset[i], i+pf->firstchar);
1006 #endif
1008 fprintf(ofp, "};\n\n");
1011 /* output width table for proportional fonts*/
1012 if (pf->width) {
1013 fprintf(ofp, "/* Character width data. */\n"
1014 "static const unsigned char _sysfont_width[] = {\n");
1016 for (i=0; i<pf->size; ++i)
1017 fprintf(ofp, " %d,\t/* (0x%02x) */\n",
1018 pf->width[i], i+pf->firstchar);
1019 fprintf(ofp, "};\n\n");
1022 /* output struct font struct*/
1023 if (pf->offset)
1024 sprintf(obuf, "_sysfont_offset,");
1025 else
1026 sprintf(obuf, "0, /* no encode table */");
1028 if (pf->width)
1029 sprintf(buf, "_sysfont_width, /* width */");
1030 else
1031 sprintf(buf, "0, /* fixed width */");
1033 fprintf(ofp, "/* Exported structure definition. */\n"
1034 "const struct font sysfont = {\n"
1035 " %d, /* maxwidth */\n"
1036 " %d, /* height */\n"
1037 " %d, /* ascent */\n"
1038 " %d, /* firstchar */\n"
1039 " %d, /* size */\n"
1040 " _font_bits, /* bits */\n"
1041 " %s /* offset */\n"
1042 " %s\n"
1043 " %d, /* defaultchar */\n"
1044 " %d /* bits_size */\n"
1045 "};\n"
1046 "#endif /* HAVE_LCD_BITMAP */\n",
1047 pf->maxwidth, pf->height,
1048 pf->ascent,
1049 pf->firstchar,
1050 pf->size,
1051 obuf,
1052 buf,
1053 pf->defaultchar,
1054 pf->bits_size);
1056 return 0;
1059 /* generate C header from in-core font*/
1060 int gen_h_header(struct font* pf, char *path)
1062 FILE *ofp;
1063 time_t t = time(0);
1064 char buf[256];
1065 char *hdr1 =
1066 "/* Generated by convbdf on %s. */\n"
1067 "#ifdef HAVE_LCD_BITMAP\n"
1068 "\n"
1069 "/* Font information*/\n"
1070 "#define SYSFONT_NAME %s\n"
1071 "#define SYSFONT_FACENAME %s\n"
1072 "#define SYSFONT_WIDTH %d\n"
1073 "#define SYSFONT_HEIGHT %d\n"
1074 "#define SYSFONT_SIZE %d\n"
1075 "#define SYSFONT_ASCENT %d\n";
1076 char *hdr2 =
1077 "#define SYSFONT_DESCENT %d\n"
1078 "#define SYSFONT_FIRST_CHAR %d\n"
1079 "#define SYSFONT_LAST_CHAR %d\n"
1080 "#define SYSFONT_DEFAULT_CHAR %d\n"
1081 "#define SYSFONT_PROPORTIONAL %d\n"
1082 "#define SYSFONT_COPYRIGHT %s\n"
1083 "#define SYSFONT_BITS_SIZE %d\n"
1084 "\n"
1085 "#endif\n";
1087 ofp = fopen(path, "w");
1088 if (!ofp) {
1089 fprintf(stderr, "Can't create %s\n", path);
1090 return 1;
1093 strcpy(buf, ctime(&t));
1094 buf[strlen(buf)-1] = 0;
1096 fprintf(ofp, hdr1, buf,
1097 pf->name,
1098 pf->facename? pf->facename: "",
1099 pf->maxwidth,
1100 pf->height,
1101 pf->size,
1102 pf->ascent);
1104 fprintf(ofp, hdr2,
1105 pf->descent,
1106 pf->firstchar,
1107 pf->firstchar+pf->size-1,
1108 pf->defaultchar,
1109 pf->width? 1: 0,
1110 pf->copyright? pf->copyright: "",
1111 pf->bits_size);
1113 return 0;
1116 static int writebyte(FILE *fp, unsigned char c)
1118 return putc(c, fp) != EOF;
1121 static int writeshort(FILE *fp, unsigned short s)
1123 putc(s, fp);
1124 return putc(s>>8, fp) != EOF;
1127 static int writeint(FILE *fp, unsigned int l)
1129 putc(l, fp);
1130 putc(l>>8, fp);
1131 putc(l>>16, fp);
1132 return putc(l>>24, fp) != EOF;
1135 static int writestr(FILE *fp, char *str, int count)
1137 return (int)fwrite(str, 1, count, fp) == count;
1140 #ifndef ROTATE
1141 static int writestrpad(FILE *fp, char *str, int totlen)
1143 int ret;
1145 while (str && *str && totlen > 0) {
1146 if (*str) {
1147 ret = putc(*str++, fp);
1148 --totlen;
1151 while (--totlen >= 0)
1152 ret = putc(' ', fp);
1153 return ret;
1155 #endif
1157 /* generate .fnt format file from in-core font*/
1158 int gen_fnt_file(struct font* pf, char *path)
1160 FILE *ofp;
1161 int i;
1162 #ifdef ROTATE
1163 int ofr = 0;
1164 #endif
1166 ofp = fopen(path, "wb");
1167 if (!ofp) {
1168 fprintf(stderr, "Can't create %s\n", path);
1169 return 1;
1172 /* write magic and version #*/
1173 writestr(ofp, VERSION, 4);
1174 #ifndef ROTATE
1175 /* internal font name*/
1176 writestrpad(ofp, pf->name, 64);
1178 /* copyright*/
1179 writestrpad(ofp, pf->copyright, 256);
1180 #endif
1181 /* font info*/
1182 writeshort(ofp, pf->maxwidth);
1183 writeshort(ofp, pf->height);
1184 writeshort(ofp, pf->ascent);
1185 writeshort(ofp, 0);
1186 writeint(ofp, pf->firstchar);
1187 writeint(ofp, pf->defaultchar);
1188 writeint(ofp, pf->size);
1190 /* variable font data sizes*/
1191 writeint(ofp, pf->bits_size); /* # words of bitmap_t*/
1192 writeint(ofp, pf->offset? pf->size: 0); /* # ints of offset*/
1193 writeint(ofp, pf->width? pf->size: 0); /* # bytes of width*/
1194 /* variable font data*/
1195 #ifdef ROTATE
1196 for (i=0; i<pf->size; ++i)
1198 bitmap_t* bits;
1199 int width = pf->width ? pf->width[i] : pf->maxwidth;
1200 int size;
1201 unsigned char bytemap[512];
1203 /* Skip missing glyphs */
1204 if (pf->offset && (pf->offset[i] == (unsigned int)-1))
1205 continue;
1207 bits = pf->bits + (pf->offset? (int)pf->offset[i]: (pf->height * i));
1209 size = rotleft(bytemap, sizeof(bytemap), bits, width, pf->height);
1210 writestr(ofp, (char *)bytemap, size);
1212 /* update offrot since bits are now in sorted order */
1213 pf->offrot[i] = ofr;
1214 ofr += size;
1217 if ( pf->bits_size < 0xFFDB )
1219 /* bitmap offset is small enough, use unsigned short for offset */
1220 if (ftell(ofp) & 1)
1221 writebyte(ofp, 0); /* pad to 16-bit boundary*/
1223 else
1225 /* bitmap offset is large then 64K, use unsigned int for offset */
1226 while (ftell(ofp) & 3)
1227 writebyte(ofp, 0); /* pad to 32-bit boundary*/
1230 if (pf->offset)
1232 for (i=0; i<pf->size; ++i)
1234 if (pf->offset[i] == (unsigned int)-1) {
1235 pf->offrot[i] = pf->offrot[pf->defaultchar - pf->firstchar];
1237 if ( pf->bits_size < 0xFFDB )
1238 writeshort(ofp, pf->offrot[i]);
1239 else
1240 writeint(ofp, pf->offrot[i]);
1244 if (pf->width)
1245 for (i=0; i<pf->size; ++i)
1246 writebyte(ofp, pf->width[i]);
1247 #else
1248 for (i=0; i<pf->bits_size; ++i)
1249 writeshort(ofp, pf->bits[i]);
1250 if (ftell(ofp) & 2)
1251 writeshort(ofp, 0); /* pad to 32-bit boundary*/
1253 if (pf->offset)
1254 for (i=0; i<pf->size; ++i) {
1255 if (pf->offset[i] == (unsigned int)-1) {
1256 pf->offset[i] = pf->offset[pf->defaultchar - pf->firstchar];
1258 writeint(ofp, pf->offset[i]);
1261 if (pf->width)
1262 for (i=0; i<pf->size; ++i)
1263 writebyte(ofp, pf->width[i]);
1264 #endif
1265 fclose(ofp);
1266 return 0;