Improve spacing in comments in convbdf; rename a local variable which can be confused...
[kugel-rb.git] / tools / convbdf.c
blobc9c43848ed70f8938d922310e4976d778781bd11
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 <stdarg.h>
14 #include <time.h>
16 #define ROTATE /* define this for the new, rotated format */
18 /* BEGIN font.h */
19 /* loadable font magic and version number */
20 #ifdef ROTATE
21 #define VERSION "RB12" /* newer version */
22 #else
23 #define VERSION "RB11"
24 #endif
27 * bitmap_t helper macros
29 typedef unsigned short bitmap_t; /* bitmap image unit size */
31 /* Number of words to hold a pixel line of width x pixels */
32 #define BITMAP_BITSPERIMAGE (sizeof(bitmap_t) * 8)
33 #define BITMAP_WORDS(x) (((x)+BITMAP_BITSPERIMAGE-1)/BITMAP_BITSPERIMAGE)
34 #define BITMAP_BYTES(x) (BITMAP_WORDS(x)*sizeof(bitmap_t))
35 #define BITMAP_BITVALUE(n) ((bitmap_t) (((bitmap_t) 1) << (n)))
36 #define BITMAP_FIRSTBIT (BITMAP_BITVALUE(BITMAP_BITSPERIMAGE - 1))
37 #define BITMAP_TESTBIT(m) ((m) & BITMAP_FIRSTBIT)
38 #define BITMAP_SHIFTBIT(m) ((bitmap_t) ((m) << 1))
41 /* builtin C-based proportional/fixed font structure */
42 /* based on The Microwindows Project http://microwindows.org */
43 struct font {
44 int maxwidth; /* max width in pixels */
45 int height; /* height in pixels */
46 int ascent; /* ascent (baseline) height */
47 int firstchar; /* first character in bitmap */
48 int size; /* font size in glyphs ('holes' included) */
49 bitmap_t* bits; /* 16-bit right-padded bitmap data */
50 int* offset; /* offsets into bitmap data */
51 unsigned char* width; /* character widths or NULL if fixed */
52 int defaultchar; /* default char (not glyph index) */
53 int bits_size; /* # words of bitmap_t bits */
55 /* unused by runtime system, read in by convbdf */
56 int nchars; /* number of different glyphs */
57 int nchars_declared; /* number of glyphs as declared in the header */
58 int ascent_declared; /* ascent as declared in the header */
59 int descent_declared; /* descent as declared in the header */
60 int max_char_ascent; /* max. char ascent (before adjusting) */
61 int max_char_descent; /* max. char descent (before adjusting) */
62 unsigned int* offrot; /* offsets into rotated bitmap data */
63 char* name; /* font name */
64 char* facename; /* facename of font */
65 char* copyright; /* copyright info for loadable fonts */
66 int pixel_size;
67 int descent;
68 int fbbw, fbbh, fbbx, fbby;
70 /* Max 'overflow' of a char's ascent (descent) over the font's one */
71 int max_over_ascent, max_over_descent;
73 /* The number of clipped ascents/descents/total */
74 int num_clipped_ascent, num_clipped_descent, num_clipped;
76 /* default width in pixels (can be overwritten at char level) */
77 int default_width;
79 /* END font.h */
81 /* Description of how the ascent/descent is allowed to grow */
82 struct stretch {
83 int value; /* The delta value (in pixels or percents) */
84 int percent; /* Is the value in percents (true) or pixels (false)? */
85 int force; /* MUST the value be set (true) or is it just a max (false) */
88 #define isprefix(buf,str) (!strncmp(buf, str, strlen(str)))
89 #define strequal(s1,s2) (!strcmp(s1, s2))
91 #define MAX(a,b) ((a) > (b) ? (a) : (b))
92 #define MIN(a,b) ((a) < (b) ? (a) : (b))
94 #ifdef ROTATE
95 #define ROTATION_BUF_SIZE 2048
96 #endif
98 /* Depending on the verbosity level some warnings are printed or not */
99 int verbosity_level = 0;
100 int trace = 0;
102 /* Prints a warning of the specified verbosity level. It will only be
103 really printed if the level is >= the level set in the settings */
104 void print_warning(int level, const char *fmt, ...);
105 void print_error(const char *fmt, ...);
106 void print_info(const char *fmt, ...);
107 void print_trace(const char *fmt, ...);
108 #define VL_CLIP_FONT 1 /* Verbosity level for clip related warnings at font level */
109 #define VL_CLIP_CHAR 2 /* Verbosity level for clip related warnings at char level */
110 #define VL_MISC 1 /* Verbosity level for other warnings */
112 int gen_c = 0;
113 int gen_h = 0;
114 int gen_fnt = 0;
115 int gen_map = 1;
116 int start_char = 0;
117 int limit_char = 65535;
118 int oflag = 0;
119 char outfile[256];
121 struct stretch stretch_ascent = { 0, 0, 1 }; /* Don't allow ascent to grow by default */
122 struct stretch stretch_descent = { 0, 0, 1 }; /* Don't allow descent to grow by default */
125 void usage(void);
126 void getopts(int *pac, char ***pav);
127 int convbdf(char *path);
129 void free_font(struct font* pf);
130 struct font* bdf_read_font(char *path);
131 int bdf_read_header(FILE *fp, struct font* pf);
132 int bdf_read_bitmaps(FILE *fp, struct font* pf);
135 Counts the glyphs and determines the max dimensions of glyphs
136 (fills the fields nchars, maxwidth, max_over_ascent, max_over_descent).
137 Returns 0 on failure or not-0 on success.
139 int bdf_analyze_font(FILE *fp, struct font* pf);
140 void bdf_correct_bbx(int *width, int *bbx); /* Corrects bbx and width if bbx<0 */
142 /* Corrects the ascent and returns the new value (value to use) */
143 int adjust_ascent(int ascent, int overflow, struct stretch *stretch);
145 char * bdf_getline(FILE *fp, char *buf, int len);
146 bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2);
148 int gen_c_source(struct font* pf, char *path);
149 int gen_h_header(struct font* pf, char *path);
150 int gen_fnt_file(struct font* pf, char *path);
152 void
153 usage(void)
155 /* We use string array because some C compilers issue warnings about too long strings */
156 char *help[] = {
157 "Usage: convbdf [options] [input-files]\n",
158 " convbdf [options] [-o output-file] [single-input-file]\n",
159 "Options:\n",
160 " -c Convert .bdf to .c source file\n",
161 " -h Convert .bdf to .h header file (to create sysfont.h)\n",
162 " -f Convert .bdf to .fnt font file\n",
163 " -s N Start output at character encodings >= N\n",
164 " -l N Limit output to character encodings <= N\n",
165 " -n Don't generate bitmaps as comments in .c file\n",
166 " -a N[%][!] Allow the ascent to grow N pixels/% to avoid glyph clipping\n",
167 " -d N[%][!] Allow the descent to grow N pixels/% to avoid glyph clipping\n",
168 " -v N Verbosity level: 0=quite quiet, 1=more verbose, 2=even more, etc.\n",
169 " -t Print internal tracing messages\n",
170 NULL /* Must be the last element in the array */
173 char **p = help;
174 while (*p != NULL)
175 print_info("%s", *(p++));
179 void parse_ascent_opt(char *val, struct stretch *opt) {
180 char buf[256];
181 char *p;
182 strcpy(buf, val);
184 opt->force = 0;
185 opt->percent = 0;
186 p = buf + strlen(buf);
187 while (p > buf) {
188 p--;
189 if (*p == '%') {
190 opt->percent = 1;
191 *p = '\0';
193 else if (*p == '!') {
194 opt->force = 1;
195 *p = '\0';
197 else {
198 break;
201 opt->value = atoi(buf);
204 /* parse command line options */
205 void getopts(int *pac, char ***pav)
207 char *p;
208 char **av;
209 int ac;
211 ac = *pac;
212 av = *pav;
213 while (ac > 0 && av[0][0] == '-') {
214 p = &av[0][1];
215 while( *p)
216 switch(*p++) {
217 case ' ': /* multiple -args on av[] */
218 while( *p && *p == ' ')
219 p++;
220 if( *p++ != '-') /* next option must have dash */
221 p = "";
222 break; /* proceed to next option */
223 case 'c': /* generate .c output */
224 gen_c = 1;
225 break;
226 case 'h': /* generate .h output */
227 gen_h = 1;
228 break;
229 case 'f': /* generate .fnt output */
230 gen_fnt = 1;
231 break;
232 case 'n': /* don't gen bitmap comments */
233 gen_map = 0;
234 break;
235 case 'o': /* set output file */
236 oflag = 1;
237 if (*p) {
238 strcpy(outfile, p);
239 while (*p && *p != ' ')
240 p++;
242 else {
243 av++; ac--;
244 if (ac > 0)
245 strcpy(outfile, av[0]);
247 break;
248 case 'l': /* set encoding limit */
249 if (*p) {
250 limit_char = atoi(p);
251 while (*p && *p != ' ')
252 p++;
254 else {
255 av++; ac--;
256 if (ac > 0)
257 limit_char = atoi(av[0]);
259 break;
260 case 's': /* set encoding start */
261 if (*p) {
262 start_char = atoi(p);
263 while (*p && *p != ' ')
264 p++;
266 else {
267 av++; ac--;
268 if (ac > 0)
269 start_char = atoi(av[0]);
271 break;
272 case 'a': /* ascent growth */
273 if (*p) {
274 parse_ascent_opt(p, &stretch_ascent);
275 while (*p && *p != ' ')
276 p++;
278 else {
279 av++; ac--;
280 if (ac > 0)
281 parse_ascent_opt(av[0], &stretch_ascent);
283 break;
284 case 'd': /* descent growth */
285 if (*p) {
286 parse_ascent_opt(p, &stretch_descent);
287 while (*p && *p != ' ')
288 p++;
290 else {
291 av++; ac--;
292 if (ac > 0)
293 parse_ascent_opt(av[0], &stretch_descent);
295 break;
296 case 'v': /* verbosity */
297 if (*p) {
298 verbosity_level = atoi(p);
299 while (*p && *p != ' ')
300 p++;
302 else {
303 av++; ac--;
304 if (ac > 0)
305 verbosity_level = atoi(av[0]);
307 break;
308 case 't': /* tracing */
309 trace = 1;
310 break;
311 default:
312 print_info("Unknown option ignored: %c\n", *(p-1));
314 ++av; --ac;
316 *pac = ac;
317 *pav = av;
320 void print_warning(int level, const char *fmt, ...) {
321 if (verbosity_level >= level) {
322 va_list ap;
323 va_start(ap, fmt);
324 fprintf(stderr, " WARN: ");
325 vfprintf(stderr, fmt, ap);
326 va_end(ap);
330 void print_trace(const char *fmt, ...) {
331 if (trace) {
332 va_list ap;
333 va_start(ap, fmt);
334 fprintf(stderr, "TRACE: ");
335 vfprintf(stderr, fmt, ap);
336 va_end(ap);
340 void print_error(const char *fmt, ...) {
341 va_list ap;
342 va_start(ap, fmt);
343 fprintf(stderr, "ERROR: ");
344 vfprintf(stderr, fmt, ap);
345 va_end(ap);
348 void print_info(const char *fmt, ...) {
349 va_list ap;
350 va_start(ap, fmt);
351 fprintf(stderr, " INFO: ");
352 vfprintf(stderr, fmt, ap);
353 va_end(ap);
356 /* remove directory prefix and file suffix from full path */
357 char *basename(char *path)
359 char *p, *b;
360 static char base[256];
362 /* remove prepended path and extension */
363 b = path;
364 for (p=path; *p; ++p) {
365 if (*p == '/')
366 b = p + 1;
368 strcpy(base, b);
369 for (p=base; *p; ++p) {
370 if (*p == '.') {
371 *p = 0;
372 break;
375 return base;
378 int convbdf(char *path)
380 struct font* pf;
381 int ret = 0;
383 pf = bdf_read_font(path);
384 if (!pf)
385 exit(1);
387 if (gen_c) {
388 if (!oflag) {
389 strcpy(outfile, basename(path));
390 strcat(outfile, ".c");
392 ret |= gen_c_source(pf, outfile);
395 if (gen_h) {
396 if (!oflag) {
397 strcpy(outfile, basename(path));
398 strcat(outfile, ".h");
400 ret |= gen_h_header(pf, outfile);
403 if (gen_fnt) {
404 if (!oflag) {
405 strcpy(outfile, basename(path));
406 strcat(outfile, ".fnt");
408 ret |= gen_fnt_file(pf, outfile);
411 free_font(pf);
412 return ret;
415 int main(int ac, char **av)
417 int ret = 0;
419 ++av; --ac; /* skip av[0] */
420 getopts(&ac, &av); /* read command line options */
422 if (ac < 1 || (!gen_c && !gen_h && !gen_fnt)) {
423 usage();
424 exit(1);
427 if (oflag) {
428 if (ac > 1 || (gen_c && gen_fnt) || (gen_c && gen_h) || (gen_h && gen_fnt)) {
429 usage();
430 exit(1);
434 while (ac > 0) {
435 ret |= convbdf(av[0]);
436 ++av; --ac;
439 exit(ret);
442 /* free font structure */
443 void free_font(struct font* pf)
445 if (!pf)
446 return;
447 if (pf->name)
448 free(pf->name);
449 if (pf->facename)
450 free(pf->facename);
451 if (pf->bits)
452 free(pf->bits);
453 if (pf->offset)
454 free(pf->offset);
455 if (pf->offrot)
456 free(pf->offrot);
457 if (pf->width)
458 free(pf->width);
459 free(pf);
462 /* build incore structure from .bdf file */
463 struct font* bdf_read_font(char *path)
465 FILE *fp;
466 struct font* pf;
468 fp = fopen(path, "rb");
469 if (!fp) {
470 print_error("Error opening file: %s\n", path);
471 return NULL;
474 pf = (struct font*)calloc(1, sizeof(struct font));
475 if (!pf)
476 goto errout;
477 memset(pf, 0, sizeof(struct font));
479 pf->name = strdup(basename(path));
481 if (!bdf_read_header(fp, pf)) {
482 print_error("Error reading font header\n");
483 goto errout;
485 print_trace("Read font header, nchars_decl=%d\n", pf->nchars_declared);
487 if (!bdf_analyze_font(fp, pf)) {
488 print_error("Error analyzing the font\n");
489 goto errout;
491 print_trace("Analyzed font, nchars=%d, maxwidth=%d, asc_over=%d, desc_over=%d\n",
492 pf->nchars, pf->maxwidth, pf->max_over_ascent, pf->max_over_descent);
494 if (pf->nchars != pf->nchars_declared) {
495 print_warning(VL_MISC, "The declared number of chars (%d) "
496 "does not match the real number (%d)\n",
497 pf->nchars_declared, pf->nchars);
500 /* Correct ascent/descent if necessary */
501 pf->ascent = adjust_ascent(pf->ascent_declared, pf->max_over_ascent, &stretch_ascent);
502 if (pf->ascent != pf->ascent_declared) {
503 print_info("Font ascent has been changed from %d to %d\n",
504 pf->ascent_declared, pf->ascent);
506 pf->descent = adjust_ascent(pf->descent, pf->max_over_descent, &stretch_descent);
507 if (pf->descent != pf->descent_declared) {
508 print_info("Font descent has been changed from %d to %d\n",
509 pf->descent_declared, pf->descent);
511 pf->height = pf->ascent + pf->descent;
512 if (pf->height != pf->ascent_declared + pf->descent_declared) {
513 print_warning(VL_CLIP_FONT, "Generated font's height: %d\n", pf->height);
516 if (pf->ascent > pf->max_char_ascent) {
517 print_trace("Font's ascent could be reduced by %d to %d without clipping\n",
518 (pf->ascent - pf->max_char_ascent), pf->max_char_ascent);
520 if (pf->descent > pf->max_char_descent) {
521 print_trace("Font's descent could be reduced by %d to %d without clipping\n",
522 (pf->descent - pf->max_char_descent), pf->max_char_descent);
526 /* Alocate memory */
527 pf->bits_size = pf->size * BITMAP_WORDS(pf->maxwidth) * pf->height;
528 pf->bits = (bitmap_t *)malloc(pf->bits_size * sizeof(bitmap_t));
529 pf->offset = (int *)malloc(pf->size * sizeof(int));
530 pf->offrot = (unsigned int *)malloc(pf->size * sizeof(unsigned int));
531 pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char));
533 if (!pf->bits || !pf->offset || !pf->offrot || !pf->width) {
534 print_error("no memory for font load\n");
535 goto errout;
538 pf->num_clipped_ascent = pf->num_clipped_descent = pf->num_clipped = 0;
539 pf->max_over_ascent = pf->max_over_descent = 0;
541 if (!bdf_read_bitmaps(fp, pf)) {
542 print_error("Error reading font bitmaps\n");
543 goto errout;
545 print_trace("Read bitmaps\n");
547 if (pf->num_clipped > 0) {
548 print_warning(VL_CLIP_FONT, "%d character(s) out of %d were clipped "
549 "(%d at ascent, %d at descent)\n",
550 pf->num_clipped, pf->nchars,
551 pf->num_clipped_ascent, pf->num_clipped_descent);
552 print_warning(VL_CLIP_FONT, "max overflows: %d pixel(s) at ascent, %d pixel(s) at descent\n",
553 pf->max_over_ascent, pf->max_over_descent);
556 fclose(fp);
557 return pf;
559 errout:
560 fclose(fp);
561 free_font(pf);
562 return NULL;
565 /* read bdf font header information, return 0 on error */
566 int bdf_read_header(FILE *fp, struct font* pf)
568 int encoding;
569 int firstchar = 65535;
570 int lastchar = -1;
571 char buf[256];
572 char facename[256];
573 char copyright[256];
574 int is_header = 1;
576 /* set certain values to errors for later error checking */
577 pf->defaultchar = -1;
578 pf->ascent = -1;
579 pf->descent = -1;
580 pf->default_width = -1;
582 for (;;) {
583 if (!bdf_getline(fp, buf, sizeof(buf))) {
584 print_error("EOF on file\n");
585 return 0;
587 if (isprefix(buf, "FONT ")) { /* not required */
588 if (sscanf(buf, "FONT %[^\n]", facename) != 1) {
589 print_error("bad 'FONT'\n");
590 return 0;
592 pf->facename = strdup(facename);
593 continue;
595 if (isprefix(buf, "COPYRIGHT ")) { /* not required */
596 if (sscanf(buf, "COPYRIGHT \"%[^\"]", copyright) != 1) {
597 print_error("bad 'COPYRIGHT'\n");
598 return 0;
600 pf->copyright = strdup(copyright);
601 continue;
603 if (isprefix(buf, "DEFAULT_CHAR ")) { /* not required */
604 if (sscanf(buf, "DEFAULT_CHAR %d", &pf->defaultchar) != 1) {
605 print_error("bad 'DEFAULT_CHAR'\n");
606 return 0;
609 if (isprefix(buf, "FONT_DESCENT ")) {
610 if (sscanf(buf, "FONT_DESCENT %d", &pf->descent_declared) != 1) {
611 print_error("bad 'FONT_DESCENT'\n");
612 return 0;
614 pf->descent = pf->descent_declared; /* For now */
615 continue;
617 if (isprefix(buf, "FONT_ASCENT ")) {
618 if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent_declared) != 1) {
619 print_error("bad 'FONT_ASCENT'\n");
620 return 0;
622 pf->ascent = pf->ascent_declared; /* For now */
623 continue;
625 if (isprefix(buf, "FONTBOUNDINGBOX ")) {
626 if (sscanf(buf, "FONTBOUNDINGBOX %d %d %d %d",
627 &pf->fbbw, &pf->fbbh, &pf->fbbx, &pf->fbby) != 4) {
628 print_error("bad 'FONTBOUNDINGBOX'\n");
629 return 0;
631 continue;
633 if (isprefix(buf, "CHARS ")) {
634 if (sscanf(buf, "CHARS %d", &pf->nchars_declared) != 1) {
635 print_error("bad 'CHARS'\n");
636 return 0;
638 continue;
640 if (isprefix(buf, "STARTCHAR")) {
641 is_header = 0;
642 continue;
645 /* for BDF version 2.2 */
646 if (is_header && isprefix(buf, "DWIDTH ")) {
647 if (sscanf(buf, "DWIDTH %d", &pf->default_width) != 1) {
648 print_error("bad 'DWIDTH' at font level\n");
649 return 0;
651 continue;
655 * Reading ENCODING is necessary to get firstchar/lastchar
656 * which is needed to pre-calculate our offset and widths
657 * array sizes.
659 if (isprefix(buf, "ENCODING ")) {
660 if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
661 print_error("bad 'ENCODING'\n");
662 return 0;
664 if (encoding >= 0 &&
665 encoding <= limit_char &&
666 encoding >= start_char) {
668 if (firstchar > encoding)
669 firstchar = encoding;
670 if (lastchar < encoding)
671 lastchar = encoding;
673 continue;
675 if (strequal(buf, "ENDFONT"))
676 break;
679 /* calc font height */
680 if (pf->ascent < 0 || pf->descent < 0 || firstchar < 0) {
681 print_error("Invalid BDF file, requires FONT_ASCENT/FONT_DESCENT/ENCODING\n");
682 return 0;
684 pf->height = pf->ascent + pf->descent;
686 /* calc default char */
687 if (pf->defaultchar < 0 ||
688 pf->defaultchar < firstchar ||
689 pf->defaultchar > limit_char ||
690 pf->defaultchar > lastchar)
691 pf->defaultchar = firstchar;
693 /* calc font size (offset/width entries) */
694 pf->firstchar = firstchar;
695 pf->size = lastchar - firstchar + 1;
697 return 1;
701 * TODO: rework the code to avoid logics duplication in
702 * bdf_read_bitmaps and bdf_analyze_font
706 /* read bdf font bitmaps, return 0 on error */
707 int bdf_read_bitmaps(FILE *fp, struct font* pf)
709 int ofs = 0;
710 int ofr = 0;
711 int i, k, encoding, width;
712 int bbw, bbh, bbx, bby;
713 int proportional = 0;
714 int encodetable = 0;
715 int offset;
716 char buf[256];
717 bitmap_t *ch_bitmap;
718 int ch_words;
720 /* reset file pointer */
721 fseek(fp, 0L, SEEK_SET);
723 /* initially mark offsets as not used */
724 for (i=0; i<pf->size; ++i)
725 pf->offset[i] = -1;
727 for (;;) {
728 if (!bdf_getline(fp, buf, sizeof(buf))) {
729 print_error("EOF on file\n");
730 return 0;
732 if (isprefix(buf, "STARTCHAR")) {
733 encoding = width = -1;
734 bbw = pf->fbbw;
735 bbh = pf->fbbh;
736 bbx = pf->fbbx;
737 bby = pf->fbby;
738 continue;
740 if (isprefix(buf, "ENCODING ")) {
741 if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
742 print_error("bad 'ENCODING'\n");
743 return 0;
745 if (encoding < start_char || encoding > limit_char)
746 encoding = -1;
747 continue;
749 if (isprefix(buf, "DWIDTH ")) {
750 if (sscanf(buf, "DWIDTH %d", &width) != 1) {
751 print_error("bad 'DWIDTH'\n");
752 return 0;
754 /* use font boundingbox width if DWIDTH <= 0 */
755 if (width <= 0)
756 width = pf->fbbw - pf->fbbx;
757 continue;
759 if (isprefix(buf, "BBX ")) {
760 if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) {
761 print_error("bad 'BBX'\n");
762 return 0;
764 continue;
766 if (strequal(buf, "BITMAP") || strequal(buf, "BITMAP ")) {
767 int overflow_asc, overflow_desc;
768 int bbh_orig, bby_orig, y;
770 if (encoding < 0)
771 continue;
773 if (width < 0 && pf->default_width > 0)
774 width = pf->default_width;
776 /* set bits offset in encode map */
777 if (pf->offset[encoding-pf->firstchar] != -1) {
778 print_error("duplicate encoding for character %d (0x%02x), ignoring duplicate\n",
779 encoding, encoding);
780 continue;
782 pf->offset[encoding-pf->firstchar] = ofs;
783 pf->offrot[encoding-pf->firstchar] = ofr;
785 /* calc char width */
786 bdf_correct_bbx(&width, &bbx);
787 pf->width[encoding-pf->firstchar] = width;
789 ch_bitmap = pf->bits + ofs;
790 ch_words = BITMAP_WORDS(width);
791 memset(ch_bitmap, 0, BITMAP_BYTES(width) * pf->height); /* clear bitmap */
793 #define BM(row,col) (*(ch_bitmap + ((row)*ch_words) + (col)))
794 #define BITMAP_NIBBLES (BITMAP_BITSPERIMAGE/4)
796 bbh_orig = bbh;
797 bby_orig = bby;
799 overflow_asc = bby + bbh - pf->ascent;
800 if (overflow_asc > 0) {
801 pf->num_clipped_ascent++;
802 if (overflow_asc > pf->max_over_ascent) {
803 pf->max_over_ascent = overflow_asc;
805 bbh = MAX(bbh - overflow_asc, 0); /* Clipped -> decrease the height */
806 print_warning(VL_CLIP_CHAR, "character %d goes %d pixel(s)"
807 " beyond the font's ascent, it will be clipped\n",
808 encoding, overflow_asc);
810 overflow_desc = -bby - pf->descent;
811 if (overflow_desc > 0) {
812 pf->num_clipped_descent++;
813 if (overflow_desc > pf->max_over_descent) {
814 pf->max_over_descent = overflow_desc;
816 bby += overflow_desc;
817 bbh = MAX(bbh - overflow_desc, 0); /* Clipped -> decrease the height */
818 print_warning(VL_CLIP_CHAR, "character %d goes %d pixel(s)"
819 " beyond the font's descent, it will be clipped\n",
820 encoding, overflow_desc);
822 if (overflow_asc > 0 || overflow_desc > 0) {
823 pf->num_clipped++;
826 y = bby_orig + bbh_orig; /* 0-based y within the char */
828 /* read bitmaps */
829 for (i=0; ; ++i) {
830 int hexnibbles;
832 if (!bdf_getline(fp, buf, sizeof(buf))) {
833 print_error("EOF reading BITMAP data for character %d\n",
834 encoding);
835 return 0;
837 if (isprefix(buf, "ENDCHAR"))
838 break;
840 y--;
841 if ((y >= pf->ascent) || (y < -pf->descent)) {
842 /* We're beyond the area that Rockbox can render -> clip */
843 --i; /* This line doesn't count */
844 continue;
847 hexnibbles = strlen(buf);
848 for (k=0; k<ch_words; ++k) {
849 int ndx = k * BITMAP_NIBBLES;
850 int padnibbles = hexnibbles - ndx;
851 bitmap_t value;
853 if (padnibbles <= 0)
854 break;
855 if (padnibbles >= (int)BITMAP_NIBBLES)
856 padnibbles = 0;
858 value = bdf_hexval((unsigned char *)buf,
859 ndx, ndx+BITMAP_NIBBLES-1-padnibbles);
860 value <<= padnibbles * BITMAP_NIBBLES;
862 BM(pf->height - pf->descent - bby - bbh + i, k) |=
863 value >> bbx;
864 /* handle overflow into next image word */
865 if (bbx) {
866 BM(pf->height - pf->descent - bby - bbh + i, k+1) =
867 value << (BITMAP_BITSPERIMAGE - bbx);
872 ofs += BITMAP_WORDS(width) * pf->height;
873 ofr += pf->width[encoding-pf->firstchar] * ((pf->height+7)/8);
875 continue;
877 if (strequal(buf, "ENDFONT"))
878 break;
881 /* change unused width values to default char values */
882 for (i=0; i<pf->size; ++i) {
883 int defchar = pf->defaultchar - pf->firstchar;
885 if (pf->offset[i] == -1)
886 pf->width[i] = pf->width[defchar];
889 /* determine whether font doesn't require encode table */
890 #ifdef ROTATE
891 offset = 0;
892 for (i=0; i<pf->size; ++i) {
893 if ((int)pf->offrot[i] != offset) {
894 encodetable = 1;
895 break;
897 offset += pf->maxwidth * ((pf->height + 7) / 8);
899 #else
900 offset = 0;
901 for (i=0; i<pf->size; ++i) {
902 if (pf->offset[i] != offset) {
903 encodetable = 1;
904 break;
906 offset += BITMAP_WORDS(pf->width[i]) * pf->height;
908 #endif
909 if (!encodetable) {
910 free(pf->offset);
911 pf->offset = NULL;
914 /* determine whether font is fixed-width */
915 for (i=0; i<pf->size; ++i) {
916 if (pf->width[i] != pf->maxwidth) {
917 proportional = 1;
918 break;
921 if (!proportional) {
922 free(pf->width);
923 pf->width = NULL;
926 /* reallocate bits array to actual bits used */
927 if (ofs < pf->bits_size) {
928 pf->bits = realloc(pf->bits, ofs * sizeof(bitmap_t));
929 pf->bits_size = ofs;
932 #ifdef ROTATE
933 pf->bits_size = ofr; /* always update, rotated is smaller */
934 #endif
936 return 1;
939 /* read the next non-comment line, returns buf or NULL if EOF */
940 char *bdf_getline(FILE *fp, char *buf, int len)
942 int c;
943 char *b;
945 for (;;) {
946 b = buf;
947 while ((c = getc(fp)) != EOF) {
948 if (c == '\r')
949 continue;
950 if (c == '\n')
951 break;
952 if (b - buf >= (len - 1))
953 break;
954 *b++ = c;
956 *b = '\0';
957 if (c == EOF && b == buf)
958 return NULL;
959 if (b != buf && !isprefix(buf, "COMMENT"))
960 break;
962 return buf;
965 void bdf_correct_bbx(int *width, int *bbx) {
966 if (*bbx < 0) {
967 /* Rockbox can't render overlapping glyphs */
968 *width -= *bbx;
969 *bbx = 0;
973 int bdf_analyze_font(FILE *fp, struct font* pf) {
974 char buf[256];
975 int encoding;
976 int width, bbw, bbh, bbx, bby, ascent, overflow;
977 int read_enc = 0, read_width = 0, read_bbx = 0, read_endchar = 1;
978 int ignore_char = 0;
980 /* reset file pointer */
981 fseek(fp, 0L, SEEK_SET);
983 pf->maxwidth = 0;
984 pf->nchars = 0;
985 pf->max_char_ascent = pf->max_char_descent = 0;
986 pf->max_over_ascent = pf->max_over_descent = 0;
988 for (;;) {
990 if (!bdf_getline(fp, buf, sizeof(buf))) {
991 print_error("EOF on file\n");
992 return 0;
994 if (isprefix(buf, "ENDFONT")) {
995 if (!read_endchar) {
996 print_error("No terminating ENDCHAR for character %d\n", encoding);
997 return 0;
999 break;
1001 if (isprefix(buf, "STARTCHAR")) {
1002 print_trace("Read STARTCHAR, nchars=%d, read_endchar=%d\n", pf->nchars, read_endchar);
1003 if (!read_endchar) {
1004 print_error("No terminating ENDCHAR for character %d\n", encoding);
1005 return 0;
1007 read_enc = read_width = read_bbx = read_endchar = 0;
1008 continue;
1010 if (isprefix(buf, "ENDCHAR")) {
1011 if (!read_enc) {
1012 print_error("ENCODING is not specified\n");
1013 return 0;
1015 ignore_char = (encoding < start_char || encoding > limit_char);
1016 if (!ignore_char) {
1017 if (!read_width && pf->default_width > 0)
1019 width = pf->default_width;
1020 read_width = 1;
1022 if (!read_width || !read_bbx) {
1023 print_error("WIDTH or BBX is not specified for character %d\n",
1024 encoding);
1026 bdf_correct_bbx(&width, &bbx);
1027 if (width > pf->maxwidth) {
1028 pf->maxwidth = width;
1031 ascent = bby + bbh;
1032 pf->max_char_ascent = MAX(pf->max_char_ascent, ascent);
1033 overflow = ascent - pf->ascent;
1034 pf->max_over_ascent = MAX(pf->max_over_ascent, overflow);
1036 ascent = -bby;
1037 pf->max_char_descent = MAX(pf->max_char_descent, ascent);
1038 overflow = ascent - pf->descent;
1039 pf->max_over_descent = MAX(pf->max_over_descent, overflow);
1041 pf->nchars++;
1042 read_endchar = 1;
1043 continue;
1045 if (isprefix(buf, "ENCODING ")) {
1046 if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
1047 print_error("bad 'ENCODING': '%s'\n", buf);
1048 return 0;
1050 read_enc = 1;
1051 continue;
1053 if (isprefix(buf, "DWIDTH ")) {
1054 if (sscanf(buf, "DWIDTH %d", &width) != 1) {
1055 print_error("bad 'DWIDTH': '%s'\n", buf);
1056 return 0;
1058 /* use font boundingbox width if DWIDTH <= 0 */
1059 if (width < 0) {
1060 print_error("Negative char width: %d\n", width);
1061 return 0;
1063 read_width = 1;
1065 if (isprefix(buf, "BBX ")) {
1066 if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) {
1067 print_error("bad 'BBX': '%s'\n", buf);
1068 return 0;
1070 read_bbx = 1;
1071 continue;
1074 return 1;
1077 int adjust_ascent(int ascent, int overflow, struct stretch *stretch) {
1078 int result;
1079 int px = stretch->value;
1080 if (stretch->percent) {
1081 px = ascent * px / 100;
1084 if (stretch->force) {
1085 result = ascent + px;
1087 else {
1088 result = ascent + MIN(overflow, px);
1090 result = MAX(result, 0);
1091 return result;
1095 /* return hex value of portion of buffer */
1096 bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2)
1098 bitmap_t val = 0;
1099 int i, c;
1101 for (i=ndx1; i<=ndx2; ++i) {
1102 c = buf[i];
1103 if (c >= '0' && c <= '9')
1104 c -= '0';
1105 else
1106 if (c >= 'A' && c <= 'F')
1107 c = c - 'A' + 10;
1108 else
1109 if (c >= 'a' && c <= 'f')
1110 c = c - 'a' + 10;
1111 else
1112 c = 0;
1113 val = (val << 4) | c;
1115 return val;
1119 #ifdef ROTATE
1122 * Take an bitmap_t bitmap and convert to Rockbox format.
1123 * Used for converting font glyphs for the time being.
1124 * Can use for standard X11 and Win32 images as well.
1125 * See format description in lcd-recorder.c
1127 * Doing it this way keeps fonts in standard formats,
1128 * as well as keeping Rockbox hw bitmap format.
1130 * Returns the size of the rotated glyph (in bytes) or a
1131 * negative value if the glyph could not be rotated.
1133 int rotleft(unsigned char *dst, /* output buffer */
1134 size_t dstlen, /* buffer size */
1135 bitmap_t *src, unsigned int width, unsigned int height,
1136 int char_code)
1138 unsigned int i,j;
1139 unsigned int src_words; /* # words of input image */
1140 unsigned int dst_mask; /* bit mask for destination */
1141 bitmap_t src_mask; /* bit mask for source */
1143 /* How large the buffer should be to hold the rotated bitmap
1144 of a glyph of size (width x height) */
1145 unsigned int needed_size = ((height + 7) / 8) * width;
1147 if (needed_size > dstlen) {
1148 print_error("Character %d: Glyph of size %d x %d can't be rotated "
1149 "(buffer size is %lu, needs %u)\n",
1150 char_code, width, height, (unsigned long)dstlen, needed_size);
1151 return -1;
1154 /* calc words of input image */
1155 src_words = BITMAP_WORDS(width) * height;
1157 /* clear background */
1158 memset(dst, 0, needed_size);
1160 dst_mask = 1;
1162 for (i=0; i < src_words; i++) {
1164 /* calc src input bit */
1165 src_mask = 1 << (sizeof (bitmap_t) * 8 - 1);
1167 /* for each input column... */
1168 for(j=0; j < width; j++) {
1170 if (src_mask == 0) /* input word done? */
1172 src_mask = 1 << (sizeof (bitmap_t) * 8 - 1);
1173 i++; /* next input word */
1176 /* if set in input, set in rotated output */
1177 if (src[i] & src_mask)
1178 dst[j] |= dst_mask;
1180 src_mask >>= 1; /* next input bit */
1183 dst_mask <<= 1; /* next output bit (row) */
1184 if (dst_mask > (1 << 7)) /* output bit > 7? */
1186 dst_mask = 1;
1187 dst += width; /* next output byte row */
1190 return needed_size; /* return result size in bytes */
1193 #endif /* ROTATE */
1196 /* generate C source from in-core font */
1197 int gen_c_source(struct font* pf, char *path)
1199 FILE *ofp;
1200 int i;
1201 time_t t = time(0);
1202 #ifdef ROTATE
1203 int ofr = 0;
1204 #else
1205 int did_syncmsg = 0;
1206 bitmap_t *ofs = pf->bits;
1207 #endif
1208 char buf[256];
1209 char obuf[256];
1210 char hdr1[] = {
1211 "/* Generated by convbdf on %s. */\n"
1212 "#include \"font.h\"\n"
1213 "#ifdef HAVE_LCD_BITMAP\n"
1214 "\n"
1215 "/* Font information:\n"
1216 " name: %s\n"
1217 " facename: %s\n"
1218 " w x h: %dx%d\n"
1219 " size: %d\n"
1220 " ascent: %d\n"
1221 " descent: %d\n"
1222 " first char: %d (0x%02x)\n"
1223 " last char: %d (0x%02x)\n"
1224 " default char: %d (0x%02x)\n"
1225 " proportional: %s\n"
1226 " %s\n"
1227 "*/\n"
1228 "\n"
1229 "/* Font character bitmap data. */\n"
1230 "static const unsigned char _font_bits[] = {\n"
1233 ofp = fopen(path, "w");
1234 if (!ofp) {
1235 print_error("Can't create %s\n", path);
1236 return 1;
1239 strcpy(buf, ctime(&t));
1240 buf[strlen(buf)-1] = 0;
1242 fprintf(ofp, hdr1, buf,
1243 pf->name,
1244 pf->facename? pf->facename: "",
1245 pf->maxwidth, pf->height,
1246 pf->size,
1247 pf->ascent, pf->descent,
1248 pf->firstchar, pf->firstchar,
1249 pf->firstchar+pf->size-1, pf->firstchar+pf->size-1,
1250 pf->defaultchar, pf->defaultchar,
1251 pf->width? "yes": "no",
1252 pf->copyright? pf->copyright: "");
1254 /* generate bitmaps */
1255 for (i=0; i<pf->size; ++i) {
1256 int x;
1257 int bitcount = 0;
1258 int width = pf->width ? pf->width[i] : pf->maxwidth;
1259 int height = pf->height;
1260 int char_code = pf->firstchar + i;
1261 bitmap_t *bits;
1262 bitmap_t bitvalue=0;
1264 /* Skip missing glyphs */
1265 if (pf->offset && (pf->offset[i] == -1))
1266 continue;
1268 bits = pf->bits + (pf->offset? (int)pf->offset[i]: (pf->height * i));
1270 fprintf(ofp, "\n/* Character %d (0x%02x):\n width %d",
1271 char_code, char_code, width);
1273 if (gen_map) {
1274 fprintf(ofp, "\n +");
1275 for (x=0; x<width; ++x) fprintf(ofp, "-");
1276 fprintf(ofp, "+\n");
1278 x = 0;
1279 while (height > 0) {
1280 if (x == 0) fprintf(ofp, " |");
1282 if (bitcount <= 0) {
1283 bitcount = BITMAP_BITSPERIMAGE;
1284 bitvalue = *bits++;
1287 fprintf(ofp, BITMAP_TESTBIT(bitvalue)? "*": " ");
1289 bitvalue = BITMAP_SHIFTBIT(bitvalue);
1290 --bitcount;
1291 if (++x == width) {
1292 fprintf(ofp, "|\n");
1293 --height;
1294 x = 0;
1295 bitcount = 0;
1298 fprintf(ofp, " +");
1299 for (x=0; x<width; ++x)
1300 fprintf(ofp, "-");
1301 fprintf(ofp, "+ */\n");
1303 else
1304 fprintf(ofp, " */\n");
1306 bits = pf->bits + (pf->offset? (int)pf->offset[i]: (pf->height * i));
1307 #ifdef ROTATE /* pre-rotated into Rockbox bitmap format */
1309 unsigned char bytemap[ROTATION_BUF_SIZE];
1310 int y8, ix=0;
1312 int size = rotleft(bytemap, sizeof(bytemap), bits, width,
1313 pf->height, char_code);
1314 if (size < 0) {
1315 return -1;
1318 for (y8=0; y8<pf->height; y8+=8) /* column rows */
1320 for (x=0; x<width; x++) {
1321 fprintf(ofp, "0x%02x, ", bytemap[ix]);
1322 ix++;
1324 fprintf(ofp, "\n");
1327 /* update offrot since bits are now in sorted order */
1328 pf->offrot[i] = ofr;
1329 ofr += size;
1331 #else
1332 for (x=BITMAP_WORDS(width)*pf->height; x>0; --x) {
1333 fprintf(ofp, "0x%04x,\n", *bits);
1334 if (!did_syncmsg && *bits++ != *ofs++) {
1335 print_warning(VL_MISC, "found encoding values in non-sorted order (not an error).\n");
1336 did_syncmsg = 1;
1339 #endif
1341 fprintf(ofp, "};\n\n");
1343 if (pf->offset) {
1344 /* output offset table */
1345 fprintf(ofp, "/* Character->glyph mapping. */\n"
1346 "static const unsigned short _sysfont_offset[] = {\n");
1348 for (i=0; i<pf->size; ++i) {
1349 int offset = pf->offset[i];
1350 int offrot = pf->offrot[i];
1351 if (offset == -1) {
1352 offset = pf->offset[pf->defaultchar - pf->firstchar];
1353 offrot = pf->offrot[pf->defaultchar - pf->firstchar];
1355 fprintf(ofp, " %d,\t/* (0x%02x) */\n",
1356 #ifdef ROTATE
1357 offrot, i+pf->firstchar);
1358 #else
1359 offset, i+pf->firstchar);
1360 #endif
1362 fprintf(ofp, "};\n\n");
1365 /* output width table for proportional fonts */
1366 if (pf->width) {
1367 fprintf(ofp, "/* Character width data. */\n"
1368 "static const unsigned char _sysfont_width[] = {\n");
1370 for (i=0; i<pf->size; ++i)
1371 fprintf(ofp, " %d,\t/* (0x%02x) */\n",
1372 pf->width[i], i+pf->firstchar);
1373 fprintf(ofp, "};\n\n");
1376 /* output struct font struct */
1377 if (pf->offset)
1378 sprintf(obuf, "_sysfont_offset,");
1379 else
1380 sprintf(obuf, "0, /* no encode table */");
1382 if (pf->width)
1383 sprintf(buf, "_sysfont_width, /* width */");
1384 else
1385 sprintf(buf, "0, /* fixed width */");
1387 fprintf(ofp, "/* Exported structure definition. */\n"
1388 "const struct font sysfont = {\n"
1389 " %d, /* maxwidth */\n"
1390 " %d, /* height */\n"
1391 " %d, /* ascent */\n"
1392 " %d, /* firstchar */\n"
1393 " %d, /* size */\n"
1394 " _font_bits, /* bits */\n"
1395 " %s /* offset */\n"
1396 " %s\n"
1397 " %d, /* defaultchar */\n"
1398 " %d, /* bits_size */\n"
1399 " -1, /* font fd */\n"
1400 " 0, /* buffer start */\n"
1401 " 0, /* ^ position */\n"
1402 " 0, /* ^ end */\n"
1403 " 0, /* ^ size */\n"
1404 " {{0,0,0,0,0},0,0,0}, /* cache */\n"
1405 " 0, /* */\n"
1406 " 0, /* */\n"
1407 " 0, /* */\n"
1408 "};\n"
1409 "#endif /* HAVE_LCD_BITMAP */\n",
1410 pf->maxwidth, pf->height,
1411 pf->ascent,
1412 pf->firstchar,
1413 pf->size,
1414 obuf,
1415 buf,
1416 pf->defaultchar,
1417 pf->bits_size);
1419 return 0;
1422 /* generate C header from in-core font */
1423 int gen_h_header(struct font* pf, char *path)
1425 FILE *ofp;
1426 time_t t = time(0);
1427 char buf[256];
1428 char *hdr1 =
1429 "/* Generated by convbdf on %s. */\n"
1430 "#ifdef HAVE_LCD_BITMAP\n"
1431 "\n"
1432 "/* Font information */\n"
1433 "#define SYSFONT_NAME %s\n"
1434 "#define SYSFONT_FACENAME %s\n"
1435 "#define SYSFONT_WIDTH %d\n"
1436 "#define SYSFONT_HEIGHT %d\n"
1437 "#define SYSFONT_SIZE %d\n"
1438 "#define SYSFONT_ASCENT %d\n";
1439 char *hdr2 =
1440 "#define SYSFONT_DESCENT %d\n"
1441 "#define SYSFONT_FIRST_CHAR %d\n"
1442 "#define SYSFONT_LAST_CHAR %d\n"
1443 "#define SYSFONT_DEFAULT_CHAR %d\n"
1444 "#define SYSFONT_PROPORTIONAL %d\n"
1445 "#define SYSFONT_COPYRIGHT %s\n"
1446 "#define SYSFONT_BITS_SIZE %d\n"
1447 "\n"
1448 "#endif\n";
1450 ofp = fopen(path, "w");
1451 if (!ofp) {
1452 print_error("Can't create %s\n", path);
1453 return 1;
1456 strcpy(buf, ctime(&t));
1457 buf[strlen(buf)-1] = 0;
1459 fprintf(ofp, hdr1, buf,
1460 pf->name,
1461 pf->facename? pf->facename: "",
1462 pf->maxwidth,
1463 pf->height,
1464 pf->size,
1465 pf->ascent);
1467 fprintf(ofp, hdr2,
1468 pf->descent,
1469 pf->firstchar,
1470 pf->firstchar+pf->size-1,
1471 pf->defaultchar,
1472 pf->width? 1: 0,
1473 pf->copyright? pf->copyright: "",
1474 pf->bits_size);
1476 return 0;
1479 static int writebyte(FILE *fp, unsigned char c)
1481 return putc(c, fp) != EOF;
1484 static int writeshort(FILE *fp, unsigned short s)
1486 putc(s, fp);
1487 return putc(s>>8, fp) != EOF;
1490 static int writeint(FILE *fp, unsigned int l)
1492 putc(l, fp);
1493 putc(l>>8, fp);
1494 putc(l>>16, fp);
1495 return putc(l>>24, fp) != EOF;
1498 static int writestr(FILE *fp, char *str, int count)
1500 return (int)fwrite(str, 1, count, fp) == count;
1503 #ifndef ROTATE
1504 static int writestrpad(FILE *fp, char *str, int totlen)
1506 int ret = EOF;
1508 while (str && *str && totlen > 0) {
1509 if (*str) {
1510 ret = putc(*str++, fp);
1511 --totlen;
1514 while (--totlen >= 0)
1515 ret = putc(' ', fp);
1516 return ret;
1518 #endif
1520 /* generate .fnt format file from in-core font */
1521 int gen_fnt_file(struct font* pf, char *path)
1523 FILE *ofp;
1524 int i;
1525 #ifdef ROTATE
1526 int ofr = 0;
1527 #endif
1529 ofp = fopen(path, "wb");
1530 if (!ofp) {
1531 print_error("Can't create %s\n", path);
1532 return 1;
1535 /* write magic and version number */
1536 writestr(ofp, VERSION, 4);
1537 #ifndef ROTATE
1538 /* internal font name */
1539 writestrpad(ofp, pf->name, 64);
1541 /* copyright */
1542 writestrpad(ofp, pf->copyright, 256);
1543 #endif
1544 /* font info */
1545 writeshort(ofp, pf->maxwidth);
1546 writeshort(ofp, pf->height);
1547 writeshort(ofp, pf->ascent);
1548 writeshort(ofp, 0);
1549 writeint(ofp, pf->firstchar);
1550 writeint(ofp, pf->defaultchar);
1551 writeint(ofp, pf->size);
1553 /* variable font data sizes */
1554 writeint(ofp, pf->bits_size); /* # words of bitmap_t */
1555 writeint(ofp, pf->offset? pf->size: 0); /* # ints of offset */
1556 writeint(ofp, pf->width? pf->size: 0); /* # bytes of width */
1557 /* variable font data */
1558 #ifdef ROTATE
1559 for (i=0; i<pf->size; ++i)
1561 bitmap_t* bits;
1562 int width = pf->width ? pf->width[i] : pf->maxwidth;
1563 int size;
1564 int char_code = pf->firstchar + i;
1565 unsigned char bytemap[ROTATION_BUF_SIZE];
1567 /* Skip missing glyphs */
1568 if (pf->offset && (pf->offset[i] == -1))
1569 continue;
1571 bits = pf->bits + (pf->offset? (int)pf->offset[i]: (pf->height * i));
1573 size = rotleft(bytemap, sizeof(bytemap), bits, width, pf->height, char_code);
1574 if (size < 0) {
1575 return -1;
1577 writestr(ofp, (char *)bytemap, size);
1579 /* update offrot since bits are now in sorted order */
1580 pf->offrot[i] = ofr;
1581 ofr += size;
1584 if ( pf->bits_size < 0xFFDB )
1586 /* bitmap offset is small enough, use unsigned short for offset */
1587 if (ftell(ofp) & 1)
1588 writebyte(ofp, 0); /* pad to 16-bit boundary */
1590 else
1592 /* bitmap offset is large then 64K, use unsigned int for offset */
1593 while (ftell(ofp) & 3)
1594 writebyte(ofp, 0); /* pad to 32-bit boundary */
1597 if (pf->offset)
1599 for (i=0; i<pf->size; ++i)
1601 int offrot = pf->offrot[i];
1602 if (pf->offset[i] == -1) {
1603 offrot = pf->offrot[pf->defaultchar - pf->firstchar];
1605 if ( pf->bits_size < 0xFFDB )
1606 writeshort(ofp, offrot);
1607 else
1608 writeint(ofp, offrot);
1612 if (pf->width)
1613 for (i=0; i<pf->size; ++i)
1614 writebyte(ofp, pf->width[i]);
1615 #else
1616 for (i=0; i<pf->bits_size; ++i)
1617 writeshort(ofp, pf->bits[i]);
1618 if (ftell(ofp) & 2)
1619 writeshort(ofp, 0); /* pad to 32-bit boundary */
1621 if (pf->offset)
1622 for (i=0; i<pf->size; ++i) {
1623 int offset = pf->offset[i];
1624 if (offset == -1) {
1625 offset = pf->offset[pf->defaultchar - pf->firstchar];
1627 writeint(ofp, offset);
1630 if (pf->width)
1631 for (i=0; i<pf->size; ++i)
1632 writebyte(ofp, pf->width[i]);
1633 #endif
1634 fclose(ofp);
1635 return 0;