A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1648 lines 50 kB view raw
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 <stdarg.h> 14#include <time.h> 15 16#define ROTATE /* define this for the new, rotated format */ 17 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 25 26/* 27 * bitmap_t helper macros 28 */ 29typedef unsigned short bitmap_t; /* bitmap image unit size */ 30 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)) 39 40#define MAX_FONTSIZE_FOR_16_BIT_OFFSETS 0xFFDB 41 42/* builtin C-based proportional/fixed font structure */ 43/* based on The Microwindows Project http://microwindows.org */ 44struct font { 45 int maxwidth; /* max width in pixels */ 46 int height; /* height in pixels */ 47 int ascent; /* ascent (baseline) height */ 48 int firstchar; /* first character in bitmap */ 49 int size; /* font size in glyphs ('holes' included) */ 50 int depth; /* depth of the font, 0=1bit 1=4bit */ 51 bitmap_t* bits; /* 16-bit right-padded bitmap data */ 52 int* offset; /* offsets into bitmap data */ 53 unsigned char* width; /* character widths or NULL if fixed */ 54 int defaultchar; /* default char (not glyph index) */ 55 int bits_size; /* # words of bitmap_t bits */ 56 57 /* unused by runtime system, read in by convbdf */ 58 int nchars; /* number of different glyphs */ 59 int nchars_declared; /* number of glyphs as declared in the header */ 60 int ascent_declared; /* ascent as declared in the header */ 61 int descent_declared; /* descent as declared in the header */ 62 int max_char_ascent; /* max. char ascent (before adjusting) */ 63 int max_char_descent; /* max. char descent (before adjusting) */ 64 unsigned int* offrot; /* offsets into rotated bitmap data */ 65 char* name; /* font name */ 66 char* facename; /* facename of font */ 67 char* copyright; /* copyright info for loadable fonts */ 68 int pixel_size; 69 int descent; 70 int fbbw, fbbh, fbbx, fbby; 71 72 /* Max 'overflow' of a char's ascent (descent) over the font's one */ 73 int max_over_ascent, max_over_descent; 74 75 /* The number of clipped ascents/descents/total */ 76 int num_clipped_ascent, num_clipped_descent, num_clipped; 77 78 /* default width in pixels (can be overwritten at char level) */ 79 int default_width; 80}; 81/* END font.h */ 82 83/* Description of how the ascent/descent is allowed to grow */ 84struct stretch { 85 int value; /* The delta value (in pixels or percents) */ 86 int percent; /* Is the value in percents (true) or pixels (false)? */ 87 int force; /* MUST the value be set (true) or is it just a max (false) */ 88}; 89 90#define isprefix(buf,str) (!strncmp(buf, str, strlen(str))) 91#define strequal(s1,s2) (!strcmp(s1, s2)) 92 93#define MAX(a,b) ((a) > (b) ? (a) : (b)) 94#define MIN(a,b) ((a) < (b) ? (a) : (b)) 95 96#ifdef ROTATE 97#define ROTATION_BUF_SIZE 2048 98#endif 99 100/* Depending on the verbosity level some warnings are printed or not */ 101int verbosity_level = 0; 102int trace = 0; 103 104/* Prints a warning of the specified verbosity level. It will only be 105 really printed if the level is >= the level set in the settings */ 106void print_warning(int level, const char *fmt, ...); 107void print_error(const char *fmt, ...); 108void print_info(const char *fmt, ...); 109void print_trace(const char *fmt, ...); 110#define VL_CLIP_FONT 1 /* Verbosity level for clip related warnings at font level */ 111#define VL_CLIP_CHAR 2 /* Verbosity level for clip related warnings at char level */ 112#define VL_MISC 1 /* Verbosity level for other warnings */ 113 114int gen_c = 0; 115int gen_h = 0; 116int gen_fnt = 0; 117int gen_map = 1; 118int start_char = 0; 119int limit_char = 0x10FFFF; 120int oflag = 0; 121char outfile[256]; 122 123struct stretch stretch_ascent = { 0, 0, 1 }; /* Don't allow ascent to grow by default */ 124struct stretch stretch_descent = { 0, 0, 1 }; /* Don't allow descent to grow by default */ 125 126 127void usage(void); 128void getopts(int *pac, char ***pav); 129int convbdf(char *path); 130 131void free_font(struct font* pf); 132struct font* bdf_read_font(char *path); 133int bdf_read_header(FILE *fp, struct font* pf); 134int bdf_read_bitmaps(FILE *fp, struct font* pf); 135 136/* 137 Counts the glyphs and determines the max dimensions of glyphs 138 (fills the fields nchars, maxwidth, max_over_ascent, max_over_descent). 139 Returns 0 on failure or not-0 on success. 140*/ 141int bdf_analyze_font(FILE *fp, struct font* pf); 142void bdf_correct_bbx(int *width, int *bbx); /* Corrects bbx and width if bbx<0 */ 143 144/* Corrects the ascent and returns the new value (value to use) */ 145int adjust_ascent(int ascent, int overflow, struct stretch *stretch); 146 147char * bdf_getline(FILE *fp, char *buf, int len); 148bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2); 149 150int gen_c_source(struct font* pf, char *path); 151int gen_h_header(struct font* pf, char *path); 152int gen_fnt_file(struct font* pf, char *path); 153 154void 155usage(void) 156{ 157 /* We use string array because some C compilers issue warnings about too long strings */ 158 char *help[] = { 159 "Usage: convbdf [options] [input-files]\n", 160 " convbdf [options] [-o output-file] [single-input-file]\n", 161 "Options:\n", 162 " -c Convert .bdf to .c source file\n", 163 " -h Convert .bdf to .h header file (to create sysfont.h)\n", 164 " -f Convert .bdf to .fnt font file\n", 165 " -s N Start output at character encodings >= N\n", 166 " -l N Limit output to character encodings <= N\n", 167 " -n Don't generate bitmaps as comments in .c file\n", 168 " -a N[%][!] Allow the ascent to grow N pixels/% to avoid glyph clipping\n", 169 " -d N[%][!] Allow the descent to grow N pixels/% to avoid glyph clipping\n", 170 " An ! in the -a and -d options forces the growth; N may be negative\n", 171 " -v N Verbosity level: 0=quite quiet, 1=more verbose, 2=even more, etc.\n", 172 " -t Print internal tracing messages\n", 173 NULL /* Must be the last element in the array */ 174 }; 175 176 char **p = help; 177 while (*p != NULL) 178 print_info("%s", *(p++)); 179} 180 181 182void parse_ascent_opt(char *val, struct stretch *opt) { 183 char buf[256]; 184 char *p; 185 strcpy(buf, val); 186 187 opt->force = 0; 188 opt->percent = 0; 189 p = buf + strlen(buf); 190 while (p > buf) { 191 p--; 192 if (*p == '%') { 193 opt->percent = 1; 194 *p = '\0'; 195 } 196 else if (*p == '!') { 197 opt->force = 1; 198 *p = '\0'; 199 } 200 else { 201 break; 202 } 203 } 204 opt->value = atoi(buf); 205} 206 207/* parse command line options */ 208void getopts(int *pac, char ***pav) 209{ 210 char *p; 211 char **av; 212 int ac; 213 214 ac = *pac; 215 av = *pav; 216 while (ac > 0 && av[0][0] == '-') { 217 p = &av[0][1]; 218 while( *p) 219 switch(*p++) { 220 case ' ': /* multiple -args on av[] */ 221 while( *p && *p == ' ') 222 p++; 223 if( *p++ != '-') /* next option must have dash */ 224 p = ""; 225 break; /* proceed to next option */ 226 case 'c': /* generate .c output */ 227 gen_c = 1; 228 break; 229 case 'h': /* generate .h output */ 230 gen_h = 1; 231 break; 232 case 'f': /* generate .fnt output */ 233 gen_fnt = 1; 234 break; 235 case 'n': /* don't gen bitmap comments */ 236 gen_map = 0; 237 break; 238 case 'o': /* set output file */ 239 oflag = 1; 240 if (*p) { 241 strcpy(outfile, p); 242 while (*p && *p != ' ') 243 p++; 244 } 245 else { 246 av++; ac--; 247 if (ac > 0) 248 strcpy(outfile, av[0]); 249 } 250 break; 251 case 'l': /* set encoding limit */ 252 if (*p) { 253 limit_char = atoi(p); 254 while (*p && *p != ' ') 255 p++; 256 } 257 else { 258 av++; ac--; 259 if (ac > 0) 260 limit_char = atoi(av[0]); 261 } 262 break; 263 case 's': /* set encoding start */ 264 if (*p) { 265 start_char = atoi(p); 266 while (*p && *p != ' ') 267 p++; 268 } 269 else { 270 av++; ac--; 271 if (ac > 0) 272 start_char = atoi(av[0]); 273 } 274 break; 275 case 'a': /* ascent growth */ 276 if (*p) { 277 parse_ascent_opt(p, &stretch_ascent); 278 while (*p && *p != ' ') 279 p++; 280 } 281 else { 282 av++; ac--; 283 if (ac > 0) 284 parse_ascent_opt(av[0], &stretch_ascent); 285 } 286 break; 287 case 'd': /* descent growth */ 288 if (*p) { 289 parse_ascent_opt(p, &stretch_descent); 290 while (*p && *p != ' ') 291 p++; 292 } 293 else { 294 av++; ac--; 295 if (ac > 0) 296 parse_ascent_opt(av[0], &stretch_descent); 297 } 298 break; 299 case 'v': /* verbosity */ 300 if (*p) { 301 verbosity_level = atoi(p); 302 while (*p && *p != ' ') 303 p++; 304 } 305 else { 306 av++; ac--; 307 if (ac > 0) 308 verbosity_level = atoi(av[0]); 309 } 310 break; 311 case 't': /* tracing */ 312 trace = 1; 313 break; 314 default: 315 print_info("Unknown option ignored: %c\n", *(p-1)); 316 } 317 ++av; --ac; 318 } 319 *pac = ac; 320 *pav = av; 321} 322 323void print_warning(int level, const char *fmt, ...) { 324 if (verbosity_level >= level) { 325 va_list ap; 326 va_start(ap, fmt); 327 fprintf(stderr, " WARN: "); 328 vfprintf(stderr, fmt, ap); 329 va_end(ap); 330 } 331} 332 333void print_trace(const char *fmt, ...) { 334 if (trace) { 335 va_list ap; 336 va_start(ap, fmt); 337 fprintf(stderr, "TRACE: "); 338 vfprintf(stderr, fmt, ap); 339 va_end(ap); 340 } 341} 342 343void print_error(const char *fmt, ...) { 344 va_list ap; 345 va_start(ap, fmt); 346 fprintf(stderr, "ERROR: "); 347 vfprintf(stderr, fmt, ap); 348 va_end(ap); 349} 350 351void print_info(const char *fmt, ...) { 352 va_list ap; 353 va_start(ap, fmt); 354 fprintf(stderr, " INFO: "); 355 vfprintf(stderr, fmt, ap); 356 va_end(ap); 357} 358 359/* remove directory prefix and file suffix from full path */ 360char *basename(char *path) 361{ 362 char *p, *b; 363 static char base[256]; 364 365 /* remove prepended path and extension */ 366 b = path; 367 for (p=path; *p; ++p) { 368 if (*p == '/') 369 b = p + 1; 370 } 371 strcpy(base, b); 372 for (p=base; *p; ++p) { 373 if (*p == '.') { 374 *p = 0; 375 break; 376 } 377 } 378 return base; 379} 380 381int convbdf(char *path) 382{ 383 struct font* pf; 384 int ret = 0; 385 386 pf = bdf_read_font(path); 387 if (!pf) 388 exit(1); 389 390 if (gen_c) { 391 if (!oflag) { 392 strcpy(outfile, basename(path)); 393 strcat(outfile, ".c"); 394 } 395 ret |= gen_c_source(pf, outfile); 396 } 397 398 if (gen_h) { 399 if (!oflag) { 400 strcpy(outfile, basename(path)); 401 strcat(outfile, ".h"); 402 } 403 ret |= gen_h_header(pf, outfile); 404 } 405 406 if (gen_fnt) { 407 if (!oflag) { 408 strcpy(outfile, basename(path)); 409 strcat(outfile, ".fnt"); 410 } 411 ret |= gen_fnt_file(pf, outfile); 412 } 413 414 free_font(pf); 415 return ret; 416} 417 418int main(int ac, char **av) 419{ 420 int ret = 0; 421 422 ++av; --ac; /* skip av[0] */ 423 getopts(&ac, &av); /* read command line options */ 424 425 if (ac < 1 || (!gen_c && !gen_h && !gen_fnt)) { 426 usage(); 427 exit(1); 428 } 429 430 if (oflag) { 431 if (ac > 1 || (gen_c && gen_fnt) || (gen_c && gen_h) || (gen_h && gen_fnt)) { 432 usage(); 433 exit(1); 434 } 435 } 436 437 while (ac > 0) { 438 ret |= convbdf(av[0]); 439 ++av; --ac; 440 } 441 442 exit(ret); 443} 444 445/* free font structure */ 446void free_font(struct font* pf) 447{ 448 if (!pf) 449 return; 450 if (pf->name) 451 free(pf->name); 452 if (pf->facename) 453 free(pf->facename); 454 if (pf->bits) 455 free(pf->bits); 456 if (pf->offset) 457 free(pf->offset); 458 if (pf->offrot) 459 free(pf->offrot); 460 if (pf->width) 461 free(pf->width); 462 free(pf); 463} 464 465/* build incore structure from .bdf file */ 466struct font* bdf_read_font(char *path) 467{ 468 FILE *fp; 469 struct font* pf; 470 471 fp = fopen(path, "rb"); 472 if (!fp) { 473 print_error("Error opening file: %s\n", path); 474 return NULL; 475 } 476 477 pf = (struct font*)calloc(1, sizeof(struct font)); 478 if (!pf) 479 goto errout; 480 memset(pf, 0, sizeof(struct font)); 481 482 pf->name = strdup(basename(path)); 483 484 if (!bdf_read_header(fp, pf)) { 485 print_error("Error reading font header\n"); 486 goto errout; 487 } 488 print_trace("Read font header, nchars_decl=%d\n", pf->nchars_declared); 489 490 if (!bdf_analyze_font(fp, pf)) { 491 print_error("Error analyzing the font\n"); 492 goto errout; 493 } 494 print_trace("Analyzed font, nchars=%d, maxwidth=%d, asc_over=%d, desc_over=%d\n", 495 pf->nchars, pf->maxwidth, pf->max_over_ascent, pf->max_over_descent); 496 497 if (pf->nchars != pf->nchars_declared) { 498 print_warning(VL_MISC, "The declared number of chars (%d) " 499 "does not match the real number (%d)\n", 500 pf->nchars_declared, pf->nchars); 501 } 502 503 /* Correct ascent/descent if necessary */ 504 pf->ascent = adjust_ascent(pf->ascent_declared, pf->max_over_ascent, &stretch_ascent); 505 if (pf->ascent != pf->ascent_declared) { 506 print_info("Font ascent has been changed from %d to %d\n", 507 pf->ascent_declared, pf->ascent); 508 } 509 pf->descent = adjust_ascent(pf->descent, pf->max_over_descent, &stretch_descent); 510 if (pf->descent != pf->descent_declared) { 511 print_info("Font descent has been changed from %d to %d\n", 512 pf->descent_declared, pf->descent); 513 } 514 pf->height = pf->ascent + pf->descent; 515 if (pf->height != pf->ascent_declared + pf->descent_declared) { 516 print_warning(VL_CLIP_FONT, "Generated font's height: %d\n", pf->height); 517 } 518 519 if (pf->ascent > pf->max_char_ascent) { 520 print_trace("Font's ascent could be reduced by %d to %d without clipping\n", 521 (pf->ascent - pf->max_char_ascent), pf->max_char_ascent); 522 } 523 if (pf->descent > pf->max_char_descent) { 524 print_trace("Font's descent could be reduced by %d to %d without clipping\n", 525 (pf->descent - pf->max_char_descent), pf->max_char_descent); 526 } 527 528 529 /* Alocate memory */ 530 pf->bits_size = pf->size * BITMAP_WORDS(pf->maxwidth) * pf->height; 531 pf->bits = (bitmap_t *)malloc(pf->bits_size * sizeof(bitmap_t)); 532 pf->offset = (int *)malloc(pf->size * sizeof(int)); 533 pf->offrot = (unsigned int *)malloc(pf->size * sizeof(unsigned int)); 534 pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char)); 535 536 if (!pf->bits || !pf->offset || !pf->offrot || !pf->width) { 537 print_error("no memory for font load\n"); 538 goto errout; 539 } 540 541 pf->num_clipped_ascent = pf->num_clipped_descent = pf->num_clipped = 0; 542 pf->max_over_ascent = pf->max_over_descent = 0; 543 544 if (!bdf_read_bitmaps(fp, pf)) { 545 print_error("Error reading font bitmaps\n"); 546 goto errout; 547 } 548 print_trace("Read bitmaps\n"); 549 550 if (pf->num_clipped > 0) { 551 print_warning(VL_CLIP_FONT, "%d character(s) out of %d were clipped " 552 "(%d at ascent, %d at descent)\n", 553 pf->num_clipped, pf->nchars, 554 pf->num_clipped_ascent, pf->num_clipped_descent); 555 print_warning(VL_CLIP_FONT, "max overflows: %d pixel(s) at ascent, %d pixel(s) at descent\n", 556 pf->max_over_ascent, pf->max_over_descent); 557 } 558 559 fclose(fp); 560 return pf; 561 562 errout: 563 fclose(fp); 564 free_font(pf); 565 return NULL; 566} 567 568/* read bdf font header information, return 0 on error */ 569int bdf_read_header(FILE *fp, struct font* pf) 570{ 571 int encoding; 572 int firstchar = 0x10FFFF; 573 int lastchar = -1; 574 char buf[256]; 575 char facename[256]; 576 char copyright[256]; 577 int is_header = 1; 578 579 /* set certain values to errors for later error checking */ 580 pf->defaultchar = -1; 581 pf->ascent = -1; 582 pf->descent = -1; 583 pf->default_width = -1; 584 585 for (;;) { 586 if (!bdf_getline(fp, buf, sizeof(buf))) { 587 print_error("EOF on file\n"); 588 return 0; 589 } 590 if (isprefix(buf, "FONT ")) { /* not required */ 591 if (sscanf(buf, "FONT %[^\n]", facename) != 1) { 592 print_error("bad 'FONT'\n"); 593 return 0; 594 } 595 pf->facename = strdup(facename); 596 continue; 597 } 598 if (isprefix(buf, "COPYRIGHT ")) { /* not required */ 599 if (sscanf(buf, "COPYRIGHT \"%[^\"]", copyright) != 1) { 600 print_error("bad 'COPYRIGHT'\n"); 601 return 0; 602 } 603 pf->copyright = strdup(copyright); 604 continue; 605 } 606 if (isprefix(buf, "DEFAULT_CHAR ")) { /* not required */ 607 if (sscanf(buf, "DEFAULT_CHAR %d", &pf->defaultchar) != 1) { 608 print_error("bad 'DEFAULT_CHAR'\n"); 609 return 0; 610 } 611 } 612 if (isprefix(buf, "FONT_DESCENT ")) { 613 if (sscanf(buf, "FONT_DESCENT %d", &pf->descent_declared) != 1) { 614 print_error("bad 'FONT_DESCENT'\n"); 615 return 0; 616 } 617 pf->descent = pf->descent_declared; /* For now */ 618 continue; 619 } 620 if (isprefix(buf, "FONT_ASCENT ")) { 621 if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent_declared) != 1) { 622 print_error("bad 'FONT_ASCENT'\n"); 623 return 0; 624 } 625 pf->ascent = pf->ascent_declared; /* For now */ 626 continue; 627 } 628 if (isprefix(buf, "FONTBOUNDINGBOX ")) { 629 if (sscanf(buf, "FONTBOUNDINGBOX %d %d %d %d", 630 &pf->fbbw, &pf->fbbh, &pf->fbbx, &pf->fbby) != 4) { 631 print_error("bad 'FONTBOUNDINGBOX'\n"); 632 return 0; 633 } 634 continue; 635 } 636 if (isprefix(buf, "CHARS ")) { 637 if (sscanf(buf, "CHARS %d", &pf->nchars_declared) != 1) { 638 print_error("bad 'CHARS'\n"); 639 return 0; 640 } 641 continue; 642 } 643 if (isprefix(buf, "STARTCHAR")) { 644 is_header = 0; 645 continue; 646 } 647 648 /* for BDF version 2.2 */ 649 if (is_header && isprefix(buf, "DWIDTH ")) { 650 if (sscanf(buf, "DWIDTH %d", &pf->default_width) != 1) { 651 print_error("bad 'DWIDTH' at font level\n"); 652 return 0; 653 } 654 continue; 655 } 656 657 /* 658 * Reading ENCODING is necessary to get firstchar/lastchar 659 * which is needed to pre-calculate our offset and widths 660 * array sizes. 661 */ 662 if (isprefix(buf, "ENCODING ")) { 663 if (sscanf(buf, "ENCODING %d", &encoding) != 1) { 664 print_error("bad 'ENCODING'\n"); 665 return 0; 666 } 667 if (encoding >= 0 && 668 encoding <= limit_char && 669 encoding >= start_char) { 670 671 if (firstchar > encoding) 672 firstchar = encoding; 673 if (lastchar < encoding) 674 lastchar = encoding; 675 } 676 continue; 677 } 678 if (strequal(buf, "ENDFONT")) 679 break; 680 } 681 682 /* calc font height */ 683 if (pf->ascent < 0 || pf->descent < 0 || firstchar < 0) { 684 print_error("Invalid BDF file, requires FONT_ASCENT/FONT_DESCENT/ENCODING\n"); 685 return 0; 686 } 687 pf->height = pf->ascent + pf->descent; 688 689 /* calc default char */ 690 if (pf->defaultchar < 0 || 691 pf->defaultchar < firstchar || 692 pf->defaultchar > limit_char || 693 pf->defaultchar > lastchar) 694 pf->defaultchar = firstchar; 695 696 /* calc font size (offset/width entries) */ 697 pf->firstchar = firstchar; 698 pf->size = lastchar - firstchar + 1; 699 700 return 1; 701} 702 703/* 704 * TODO: rework the code to avoid logics duplication in 705 * bdf_read_bitmaps and bdf_analyze_font 706 */ 707 708 709/* read bdf font bitmaps, return 0 on error */ 710int bdf_read_bitmaps(FILE *fp, struct font* pf) 711{ 712 int ofs = 0; 713 int ofr = 0; 714 int i, k, encoding, width; 715 int bbw, bbh, bbx, bby; 716 int proportional = 0; 717 int encodetable = 0; 718 int offset; 719 char buf[256]; 720 bitmap_t *ch_bitmap; 721 int ch_words; 722 723 /* reset file pointer */ 724 fseek(fp, 0L, SEEK_SET); 725 726 /* initially mark offsets as not used */ 727 for (i=0; i<pf->size; ++i) 728 pf->offset[i] = -1; 729 730 for (;;) { 731 if (!bdf_getline(fp, buf, sizeof(buf))) { 732 print_error("EOF on file\n"); 733 return 0; 734 } 735 if (isprefix(buf, "STARTCHAR")) { 736 encoding = width = -1; 737 bbw = pf->fbbw; 738 bbh = pf->fbbh; 739 bbx = pf->fbbx; 740 bby = pf->fbby; 741 continue; 742 } 743 if (isprefix(buf, "ENCODING ")) { 744 if (sscanf(buf, "ENCODING %d", &encoding) != 1) { 745 print_error("bad 'ENCODING'\n"); 746 return 0; 747 } 748 if (encoding < start_char || encoding > limit_char) 749 encoding = -1; 750 continue; 751 } 752 if (isprefix(buf, "DWIDTH ")) { 753 if (sscanf(buf, "DWIDTH %d", &width) != 1) { 754 print_error("bad 'DWIDTH'\n"); 755 return 0; 756 } 757 /* use font boundingbox width if DWIDTH <= 0 */ 758 if (width <= 0) 759 width = pf->fbbw - pf->fbbx; 760 continue; 761 } 762 if (isprefix(buf, "BBX ")) { 763 if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) { 764 print_error("bad 'BBX'\n"); 765 return 0; 766 } 767 continue; 768 } 769 if (strequal(buf, "BITMAP") || strequal(buf, "BITMAP ")) { 770 int overflow_asc, overflow_desc; 771 int bbh_orig, bby_orig, y; 772 773 if (encoding < 0) 774 continue; 775 776 if (width < 0 && pf->default_width > 0) 777 width = pf->default_width; 778 779 /* set bits offset in encode map */ 780 if (pf->offset[encoding-pf->firstchar] != -1) { 781 print_error("duplicate encoding for character %d (0x%02x), ignoring duplicate\n", 782 encoding, encoding); 783 continue; 784 } 785 pf->offset[encoding-pf->firstchar] = ofs; 786 pf->offrot[encoding-pf->firstchar] = ofr; 787 788 /* calc char width */ 789 bdf_correct_bbx(&width, &bbx); 790 pf->width[encoding-pf->firstchar] = width; 791 792 ch_bitmap = pf->bits + ofs; 793 ch_words = BITMAP_WORDS(width); 794 memset(ch_bitmap, 0, BITMAP_BYTES(width) * pf->height); /* clear bitmap */ 795 796#define BM(row,col) (*(ch_bitmap + ((row)*ch_words) + (col))) 797#define BITMAP_NIBBLES (BITMAP_BITSPERIMAGE/4) 798 799 bbh_orig = bbh; 800 bby_orig = bby; 801 802 overflow_asc = bby + bbh - pf->ascent; 803 if (overflow_asc > 0) { 804 pf->num_clipped_ascent++; 805 if (overflow_asc > pf->max_over_ascent) { 806 pf->max_over_ascent = overflow_asc; 807 } 808 bbh = MAX(bbh - overflow_asc, 0); /* Clipped -> decrease the height */ 809 print_warning(VL_CLIP_CHAR, "character %d goes %d pixel(s)" 810 " beyond the font's ascent, it will be clipped\n", 811 encoding, overflow_asc); 812 } 813 overflow_desc = -bby - pf->descent; 814 if (overflow_desc > 0) { 815 pf->num_clipped_descent++; 816 if (overflow_desc > pf->max_over_descent) { 817 pf->max_over_descent = overflow_desc; 818 } 819 bby += overflow_desc; 820 bbh = MAX(bbh - overflow_desc, 0); /* Clipped -> decrease the height */ 821 print_warning(VL_CLIP_CHAR, "character %d goes %d pixel(s)" 822 " beyond the font's descent, it will be clipped\n", 823 encoding, overflow_desc); 824 } 825 if (overflow_asc > 0 || overflow_desc > 0) { 826 pf->num_clipped++; 827 } 828 829 y = bby_orig + bbh_orig; /* 0-based y within the char */ 830 831 /* read bitmaps */ 832 for (i=0; ; ++i) { 833 int hexnibbles; 834 835 if (!bdf_getline(fp, buf, sizeof(buf))) { 836 print_error("EOF reading BITMAP data for character %d\n", 837 encoding); 838 return 0; 839 } 840 if (isprefix(buf, "ENDCHAR")) 841 break; 842 843 y--; 844 if ((y >= pf->ascent) || (y < -pf->descent)) { 845 /* We're beyond the area that Rockbox can render -> clip */ 846 --i; /* This line doesn't count */ 847 continue; 848 } 849 850 hexnibbles = strlen(buf); 851 for (k=0; k<ch_words; ++k) { 852 int ndx = k * BITMAP_NIBBLES; 853 int padnibbles = hexnibbles - ndx; 854 bitmap_t value; 855 856 if (padnibbles <= 0) 857 break; 858 if (padnibbles >= (int)BITMAP_NIBBLES) 859 padnibbles = 0; 860 861 value = bdf_hexval((unsigned char *)buf, 862 ndx, ndx+BITMAP_NIBBLES-1-padnibbles); 863 value <<= padnibbles * BITMAP_NIBBLES; 864 865 BM(pf->height - pf->descent - bby - bbh + i, k) |= 866 value >> bbx; 867 /* handle overflow into next image word */ 868 if (bbx) { 869 BM(pf->height - pf->descent - bby - bbh + i, k+1) = 870 value << (BITMAP_BITSPERIMAGE - bbx); 871 } 872 } 873 } 874 875 ofs += BITMAP_WORDS(width) * pf->height; 876 ofr += pf->width[encoding-pf->firstchar] * ((pf->height+7)/8); 877 878 continue; 879 } 880 if (strequal(buf, "ENDFONT")) 881 break; 882 } 883 884 /* change unused width values to default char values */ 885 for (i=0; i<pf->size; ++i) { 886 int defchar = pf->defaultchar - pf->firstchar; 887 888 if (pf->offset[i] == -1) 889 pf->width[i] = pf->width[defchar]; 890 } 891 892 /* determine whether font doesn't require encode table */ 893#ifdef ROTATE 894 offset = 0; 895 for (i=0; i<pf->size; ++i) { 896 if ((int)pf->offrot[i] != offset) { 897 encodetable = 1; 898 break; 899 } 900 offset += pf->maxwidth * ((pf->height + 7) / 8); 901 } 902#else 903 offset = 0; 904 for (i=0; i<pf->size; ++i) { 905 if (pf->offset[i] != offset) { 906 encodetable = 1; 907 break; 908 } 909 offset += BITMAP_WORDS(pf->width[i]) * pf->height; 910 } 911#endif 912 if (!encodetable) { 913 free(pf->offset); 914 pf->offset = NULL; 915 } 916 917 /* determine whether font is fixed-width */ 918 for (i=0; i<pf->size; ++i) { 919 if (pf->width[i] != pf->maxwidth) { 920 proportional = 1; 921 break; 922 } 923 } 924 if (!proportional) { 925 free(pf->width); 926 pf->width = NULL; 927 } 928 929 /* reallocate bits array to actual bits used */ 930 if (ofs < pf->bits_size) { 931 pf->bits = realloc(pf->bits, ofs * sizeof(bitmap_t)); 932 pf->bits_size = ofs; 933 } 934 935#ifdef ROTATE 936 pf->bits_size = ofr; /* always update, rotated is smaller */ 937#endif 938 939 return 1; 940} 941 942/* read the next non-comment line, returns buf or NULL if EOF */ 943char *bdf_getline(FILE *fp, char *buf, int len) 944{ 945 int c; 946 char *b; 947 948 for (;;) { 949 b = buf; 950 while ((c = getc(fp)) != EOF) { 951 if (c == '\r') 952 continue; 953 if (c == '\n') 954 break; 955 if (b - buf >= (len - 1)) 956 break; 957 *b++ = c; 958 } 959 *b = '\0'; 960 if (c == EOF && b == buf) 961 return NULL; 962 if (b != buf && !isprefix(buf, "COMMENT")) 963 break; 964 } 965 return buf; 966} 967 968void bdf_correct_bbx(int *width, int *bbx) { 969 if (*bbx < 0) { 970 /* Rockbox can't render overlapping glyphs */ 971 *width -= *bbx; 972 *bbx = 0; 973 } 974} 975 976int bdf_analyze_font(FILE *fp, struct font* pf) { 977 char buf[256]; 978 int encoding; 979 int width, bbw, bbh, bbx, bby, ascent, overflow; 980 int read_enc = 0, read_width = 0, read_bbx = 0, read_endchar = 1; 981 int ignore_char = 0; 982 983 /* reset file pointer */ 984 fseek(fp, 0L, SEEK_SET); 985 986 pf->maxwidth = 0; 987 pf->nchars = 0; 988 pf->max_char_ascent = pf->max_char_descent = 0; 989 pf->max_over_ascent = pf->max_over_descent = 0; 990 991 for (;;) { 992 993 if (!bdf_getline(fp, buf, sizeof(buf))) { 994 print_error("EOF on file\n"); 995 return 0; 996 } 997 if (isprefix(buf, "ENDFONT")) { 998 if (!read_endchar) { 999 print_error("No terminating ENDCHAR for character %d\n", encoding); 1000 return 0; 1001 } 1002 break; 1003 } 1004 if (isprefix(buf, "STARTCHAR")) { 1005 print_trace("Read STARTCHAR, nchars=%d, read_endchar=%d\n", pf->nchars, read_endchar); 1006 if (!read_endchar) { 1007 print_error("No terminating ENDCHAR for character %d\n", encoding); 1008 return 0; 1009 } 1010 read_enc = read_width = read_bbx = read_endchar = 0; 1011 continue; 1012 } 1013 if (isprefix(buf, "ENDCHAR")) { 1014 if (!read_enc) { 1015 print_error("ENCODING is not specified\n"); 1016 return 0; 1017 } 1018 ignore_char = (encoding < start_char || encoding > limit_char); 1019 if (!ignore_char) { 1020 if (!read_width && pf->default_width > 0) 1021 { 1022 width = pf->default_width; 1023 read_width = 1; 1024 } 1025 if (!read_width || !read_bbx) { 1026 print_error("WIDTH or BBX is not specified for character %d\n", 1027 encoding); 1028 } 1029 bdf_correct_bbx(&width, &bbx); 1030 if (width > pf->maxwidth) { 1031 pf->maxwidth = width; 1032 } 1033 1034 ascent = bby + bbh; 1035 pf->max_char_ascent = MAX(pf->max_char_ascent, ascent); 1036 overflow = ascent - pf->ascent; 1037 pf->max_over_ascent = MAX(pf->max_over_ascent, overflow); 1038 1039 ascent = -bby; 1040 pf->max_char_descent = MAX(pf->max_char_descent, ascent); 1041 overflow = ascent - pf->descent; 1042 pf->max_over_descent = MAX(pf->max_over_descent, overflow); 1043 } 1044 pf->nchars++; 1045 read_endchar = 1; 1046 continue; 1047 } 1048 if (isprefix(buf, "ENCODING ")) { 1049 if (sscanf(buf, "ENCODING %d", &encoding) != 1) { 1050 print_error("bad 'ENCODING': '%s'\n", buf); 1051 return 0; 1052 } 1053 read_enc = 1; 1054 continue; 1055 } 1056 if (isprefix(buf, "DWIDTH ")) { 1057 if (sscanf(buf, "DWIDTH %d", &width) != 1) { 1058 print_error("bad 'DWIDTH': '%s'\n", buf); 1059 return 0; 1060 } 1061 /* use font boundingbox width if DWIDTH <= 0 */ 1062 if (width < 0) { 1063 print_error("Negative char width: %d\n", width); 1064 return 0; 1065 } 1066 read_width = 1; 1067 } 1068 if (isprefix(buf, "BBX ")) { 1069 if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) { 1070 print_error("bad 'BBX': '%s'\n", buf); 1071 return 0; 1072 } 1073 read_bbx = 1; 1074 continue; 1075 } 1076 } 1077 return 1; 1078} 1079 1080int adjust_ascent(int ascent, int overflow, struct stretch *stretch) { 1081 int result; 1082 int px = stretch->value; 1083 if (stretch->percent) { 1084 px = ascent * px / 100; 1085 } 1086 1087 if (stretch->force) { 1088 result = ascent + px; 1089 } 1090 else { 1091 result = ascent + MIN(overflow, px); 1092 } 1093 result = MAX(result, 0); 1094 return result; 1095} 1096 1097 1098/* return hex value of portion of buffer */ 1099bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2) 1100{ 1101 bitmap_t val = 0; 1102 int i, c; 1103 1104 for (i=ndx1; i<=ndx2; ++i) { 1105 c = buf[i]; 1106 if (c >= '0' && c <= '9') 1107 c -= '0'; 1108 else 1109 if (c >= 'A' && c <= 'F') 1110 c = c - 'A' + 10; 1111 else 1112 if (c >= 'a' && c <= 'f') 1113 c = c - 'a' + 10; 1114 else 1115 c = 0; 1116 val = (val << 4) | c; 1117 } 1118 return val; 1119} 1120 1121 1122#ifdef ROTATE 1123 1124/* 1125 * Take an bitmap_t bitmap and convert to Rockbox format. 1126 * Used for converting font glyphs for the time being. 1127 * Can use for standard X11 and Win32 images as well. 1128 * See format description in lcd-recorder.c 1129 * 1130 * Doing it this way keeps fonts in standard formats, 1131 * as well as keeping Rockbox hw bitmap format. 1132 * 1133 * Returns the size of the rotated glyph (in bytes) or a 1134 * negative value if the glyph could not be rotated. 1135 */ 1136int rotleft(unsigned char *dst, /* output buffer */ 1137 size_t dstlen, /* buffer size */ 1138 bitmap_t *src, unsigned int width, unsigned int height, 1139 int char_code) 1140{ 1141 unsigned int i,j; 1142 unsigned int src_words; /* # words of input image */ 1143 unsigned int dst_mask; /* bit mask for destination */ 1144 bitmap_t src_mask; /* bit mask for source */ 1145 1146 /* How large the buffer should be to hold the rotated bitmap 1147 of a glyph of size (width x height) */ 1148 unsigned int needed_size = ((height + 7) / 8) * width; 1149 1150 if (needed_size > dstlen) { 1151 print_error("Character %d: Glyph of size %d x %d can't be rotated " 1152 "(buffer size is %lu, needs %u)\n", 1153 char_code, width, height, (unsigned long)dstlen, needed_size); 1154 return -1; 1155 } 1156 1157 /* calc words of input image */ 1158 src_words = BITMAP_WORDS(width) * height; 1159 1160 /* clear background */ 1161 memset(dst, 0, needed_size); 1162 1163 dst_mask = 1; 1164 1165 for (i=0; i < src_words; i++) { 1166 1167 /* calc src input bit */ 1168 src_mask = 1 << (sizeof (bitmap_t) * 8 - 1); 1169 1170 /* for each input column... */ 1171 for(j=0; j < width; j++) { 1172 1173 if (src_mask == 0) /* input word done? */ 1174 { 1175 src_mask = 1 << (sizeof (bitmap_t) * 8 - 1); 1176 i++; /* next input word */ 1177 } 1178 1179 /* if set in input, set in rotated output */ 1180 if (src[i] & src_mask) 1181 dst[j] |= dst_mask; 1182 1183 src_mask >>= 1; /* next input bit */ 1184 } 1185 1186 dst_mask <<= 1; /* next output bit (row) */ 1187 if (dst_mask > (1 << 7)) /* output bit > 7? */ 1188 { 1189 dst_mask = 1; 1190 dst += width; /* next output byte row */ 1191 } 1192 } 1193 return needed_size; /* return result size in bytes */ 1194} 1195 1196#endif /* ROTATE */ 1197 1198 1199/* generate C source from in-core font */ 1200int gen_c_source(struct font* pf, char *path) 1201{ 1202 FILE *ofp; 1203 int i; 1204 time_t t = time(0); 1205#ifdef ROTATE 1206 int ofr = 0; 1207#else 1208 int did_syncmsg = 0; 1209 bitmap_t *ofs = pf->bits; 1210#endif 1211 char buf[256]; 1212 char obuf[256]; 1213 char hdr1[] = { 1214 "/* Generated by convbdf on %s. */\n" 1215 "#include <stdbool.h>\n" 1216 "#include \"config.h\"\n" 1217 "#include \"font.h\"\n" 1218 "\n" 1219 "/* Font information:\n" 1220 " name: %s\n" 1221 " facename: %s\n" 1222 " w x h: %dx%d\n" 1223 " size: %d\n" 1224 " ascent: %d\n" 1225 " descent: %d\n" 1226 " depth: %d\n" 1227 " first char: %d (0x%02x)\n" 1228 " last char: %d (0x%02x)\n" 1229 " default char: %d (0x%02x)\n" 1230 " proportional: %s\n" 1231 " %s\n" 1232 "*/\n" 1233 "\n" 1234 "/* Font character bitmap data. */\n" 1235 "static const unsigned char _font_bits[] = {\n" 1236 }; 1237 1238 ofp = fopen(path, "w"); 1239 if (!ofp) { 1240 print_error("Can't create %s\n", path); 1241 return 1; 1242 } 1243 1244 strcpy(buf, ctime(&t)); 1245 buf[strlen(buf)-1] = 0; 1246 1247 fprintf(ofp, hdr1, buf, 1248 pf->name, 1249 pf->facename? pf->facename: "", 1250 pf->maxwidth, pf->height, 1251 pf->size, 1252 pf->ascent, pf->descent, pf->depth, 1253 pf->firstchar, pf->firstchar, 1254 pf->firstchar+pf->size-1, pf->firstchar+pf->size-1, 1255 pf->defaultchar, pf->defaultchar, 1256 pf->width? "yes": "no", 1257 pf->copyright? pf->copyright: ""); 1258 1259 /* generate bitmaps */ 1260 for (i=0; i<pf->size; ++i) { 1261 int x; 1262 int bitcount = 0; 1263 int width = pf->width ? pf->width[i] : pf->maxwidth; 1264 int height = pf->height; 1265 int char_code = pf->firstchar + i; 1266 bitmap_t *bits; 1267 bitmap_t bitvalue=0; 1268 1269 /* Skip missing glyphs */ 1270 if (pf->offset && (pf->offset[i] == -1)) 1271 continue; 1272 1273 bits = pf->bits + (pf->offset? (int)pf->offset[i]: (pf->height * i)); 1274 1275 fprintf(ofp, "\n/* Character %d (0x%02x):\n width %d", 1276 char_code, char_code, width); 1277 1278 if (gen_map) { 1279 fprintf(ofp, "\n +"); 1280 for (x=0; x<width; ++x) fprintf(ofp, "-"); 1281 fprintf(ofp, "+\n"); 1282 1283 x = 0; 1284 while (height > 0) { 1285 if (x == 0) fprintf(ofp, " |"); 1286 1287 if (bitcount <= 0) { 1288 bitcount = BITMAP_BITSPERIMAGE; 1289 bitvalue = *bits++; 1290 } 1291 1292 fprintf(ofp, BITMAP_TESTBIT(bitvalue)? "*": " "); 1293 1294 bitvalue = BITMAP_SHIFTBIT(bitvalue); 1295 --bitcount; 1296 if (++x == width) { 1297 fprintf(ofp, "|\n"); 1298 --height; 1299 x = 0; 1300 bitcount = 0; 1301 } 1302 } 1303 fprintf(ofp, " +"); 1304 for (x=0; x<width; ++x) 1305 fprintf(ofp, "-"); 1306 fprintf(ofp, "+ */\n"); 1307 } 1308 else 1309 fprintf(ofp, " */\n"); 1310 1311 bits = pf->bits + (pf->offset? (int)pf->offset[i]: (pf->height * i)); 1312#ifdef ROTATE /* pre-rotated into Rockbox bitmap format */ 1313 { 1314 unsigned char bytemap[ROTATION_BUF_SIZE]; 1315 int y8, ix=0; 1316 1317 int size = rotleft(bytemap, sizeof(bytemap), bits, width, 1318 pf->height, char_code); 1319 if (size < 0) { 1320 return -1; 1321 } 1322 1323 for (y8=0; y8<pf->height; y8+=8) /* column rows */ 1324 { 1325 for (x=0; x<width; x++) { 1326 fprintf(ofp, "0x%02x, ", bytemap[ix]); 1327 ix++; 1328 } 1329 fprintf(ofp, "\n"); 1330 } 1331 1332 /* update offrot since bits are now in sorted order */ 1333 pf->offrot[i] = ofr; 1334 ofr += size; 1335 } 1336#else 1337 for (x=BITMAP_WORDS(width)*pf->height; x>0; --x) { 1338 fprintf(ofp, "0x%04x,\n", *bits); 1339 if (!did_syncmsg && *bits++ != *ofs++) { 1340 print_warning(VL_MISC, "found encoding values in non-sorted order (not an error).\n"); 1341 did_syncmsg = 1; 1342 } 1343 } 1344#endif 1345 } 1346 fprintf(ofp, "};\n\n"); 1347 1348 if (pf->offset) { 1349 /* output offset table */ 1350 fprintf(ofp, "/* Character->glyph mapping. */\n" 1351 "static const unsigned %s _sysfont_offset[] = {\n", pf->bits_size > MAX_FONTSIZE_FOR_16_BIT_OFFSETS ? "long" : "short"); 1352 1353 for (i=0; i<pf->size; ++i) { 1354 int offset = pf->offset[i]; 1355 int offrot = pf->offrot[i]; 1356 if (offset == -1) { 1357 offset = pf->offset[pf->defaultchar - pf->firstchar]; 1358 offrot = pf->offrot[pf->defaultchar - pf->firstchar]; 1359 } 1360 fprintf(ofp, " %d,\t/* (0x%02x) */\n", 1361#ifdef ROTATE 1362 offrot, i+pf->firstchar); 1363#else 1364 offset, i+pf->firstchar); 1365#endif 1366 } 1367 fprintf(ofp, "};\n\n"); 1368 } 1369 1370 /* output width table for proportional fonts */ 1371 if (pf->width) { 1372 fprintf(ofp, "/* Character width data. */\n" 1373 "static const unsigned char _sysfont_width[] = {\n"); 1374 1375 for (i=0; i<pf->size; ++i) 1376 fprintf(ofp, " %d,\t/* (0x%02x) */\n", 1377 pf->width[i], i+pf->firstchar); 1378 fprintf(ofp, "};\n\n"); 1379 } 1380 1381 /* output struct font struct */ 1382 if (pf->offset) 1383 sprintf(obuf, "_sysfont_offset,"); 1384 else 1385 sprintf(obuf, "0, /* no encode table */"); 1386 1387 if (pf->width) 1388 sprintf(buf, "_sysfont_width, /* width */"); 1389 else 1390 sprintf(buf, "0, /* fixed width */"); 1391 1392 fprintf(ofp, "/* Exported structure definition. */\n" 1393 "const struct font sysfont = {\n" 1394 " %d, /* maxwidth */\n" 1395 " %d, /* height */\n" 1396 " %d, /* ascent */\n" 1397 " %d, /* firstchar */\n" 1398 " %d, /* size */\n" 1399 " %d, /* depth */\n" 1400 " _font_bits, /* bits */\n" 1401 " %s /* offset */\n" 1402 " %s\n" 1403 " %d, /* defaultchar */\n" 1404 " %d, /* bits_size */\n", 1405 pf->maxwidth, pf->height, 1406 pf->ascent, 1407 pf->firstchar, 1408 pf->size, 0, 1409 obuf, 1410 buf, 1411 pf->defaultchar, 1412 pf->bits_size 1413 ); 1414 1415 fprintf(ofp, " -1, /* font fd */\n" 1416 " -1, /* font fd width */\n" 1417 " -1, /* font fd offset */\n" 1418 " -1, /* font handle */\n" 1419 " 0, /* buffer start */\n" 1420 " 0, /* ^ position */\n" 1421 " 0, /* ^ end */\n" 1422 " 0, /* ^ size */\n" 1423 " false, /* disabled */\n" 1424 " {{0,0,0,0,0},0,0,0,0,0}, /* cache */\n" 1425 " 0, /* */\n" 1426 " 0, /* */\n" 1427 " 0, /* */\n" 1428 "};\n" 1429 ); 1430 1431 return 0; 1432} 1433 1434/* generate C header from in-core font */ 1435int gen_h_header(struct font* pf, char *path) 1436{ 1437 FILE *ofp; 1438 time_t t = time(0); 1439 char buf[256]; 1440 char *hdr1 = 1441 "/* Generated by convbdf on %s. */\n" 1442 "\n" 1443 "/* Font information */\n" 1444 "#define SYSFONT_NAME %s\n" 1445 "#define SYSFONT_FACENAME %s\n" 1446 "#define SYSFONT_WIDTH %d\n" 1447 "#define SYSFONT_HEIGHT %d\n" 1448 "#define SYSFONT_SIZE %d\n" 1449 "#define SYSFONT_ASCENT %d\n" 1450 "#define SYSFONT_DEPTH %d\n"; 1451 char *hdr2 = 1452 "#define SYSFONT_DESCENT %d\n" 1453 "#define SYSFONT_FIRST_CHAR %d\n" 1454 "#define SYSFONT_LAST_CHAR %d\n" 1455 "#define SYSFONT_DEFAULT_CHAR %d\n" 1456 "#define SYSFONT_PROPORTIONAL %d\n" 1457 "#define SYSFONT_COPYRIGHT %s\n" 1458 "#define SYSFONT_BITS_SIZE %d\n" 1459 "\n"; 1460 1461 ofp = fopen(path, "w"); 1462 if (!ofp) { 1463 print_error("Can't create %s\n", path); 1464 return 1; 1465 } 1466 1467 strcpy(buf, ctime(&t)); 1468 buf[strlen(buf)-1] = 0; 1469 1470 fprintf(ofp, hdr1, buf, 1471 pf->name, 1472 pf->facename? pf->facename: "", 1473 pf->maxwidth, 1474 pf->height, 1475 pf->size, 1476 pf->ascent, 1477 pf->depth); 1478 1479 fprintf(ofp, hdr2, 1480 pf->descent, 1481 pf->firstchar, 1482 pf->firstchar+pf->size-1, 1483 pf->defaultchar, 1484 pf->width? 1: 0, 1485 pf->copyright? pf->copyright: "", 1486 pf->bits_size); 1487 1488 return 0; 1489} 1490 1491static int writebyte(FILE *fp, unsigned char c) 1492{ 1493 return putc(c, fp) != EOF; 1494} 1495 1496static int writeshort(FILE *fp, unsigned short s) 1497{ 1498 putc(s, fp); 1499 return putc(s>>8, fp) != EOF; 1500} 1501 1502static int writeint(FILE *fp, unsigned int l) 1503{ 1504 putc(l, fp); 1505 putc(l>>8, fp); 1506 putc(l>>16, fp); 1507 return putc(l>>24, fp) != EOF; 1508} 1509 1510static int writestr(FILE *fp, char *str, int count) 1511{ 1512 return (int)fwrite(str, 1, count, fp) == count; 1513} 1514 1515#ifndef ROTATE 1516static int writestrpad(FILE *fp, char *str, int totlen) 1517{ 1518 int ret = EOF; 1519 1520 while (str && *str && totlen > 0) { 1521 if (*str) { 1522 ret = putc(*str++, fp); 1523 --totlen; 1524 } 1525 } 1526 while (--totlen >= 0) 1527 ret = putc(' ', fp); 1528 return ret; 1529} 1530#endif 1531 1532/* generate .fnt format file from in-core font */ 1533int gen_fnt_file(struct font* pf, char *path) 1534{ 1535 FILE *ofp; 1536 int i; 1537#ifdef ROTATE 1538 int ofr = 0; 1539#endif 1540 1541 ofp = fopen(path, "wb"); 1542 if (!ofp) { 1543 print_error("Can't create %s\n", path); 1544 return 1; 1545 } 1546 1547 /* write magic and version number */ 1548 writestr(ofp, VERSION, 4); 1549#ifndef ROTATE 1550 /* internal font name */ 1551 writestrpad(ofp, pf->name, 64); 1552 1553 /* copyright */ 1554 writestrpad(ofp, pf->copyright, 256); 1555#endif 1556 /* font info */ 1557 writeshort(ofp, pf->maxwidth); 1558 writeshort(ofp, pf->height); 1559 writeshort(ofp, pf->ascent); 1560 writeshort(ofp, 0); /* depth = 0 for bdffonts */ 1561 writeint(ofp, pf->firstchar); 1562 writeint(ofp, pf->defaultchar); 1563 writeint(ofp, pf->size); 1564 1565 /* variable font data sizes */ 1566 writeint(ofp, pf->bits_size); /* # words of bitmap_t */ 1567 writeint(ofp, pf->offset? pf->size: 0); /* # ints of offset */ 1568 writeint(ofp, pf->width? pf->size: 0); /* # bytes of width */ 1569 /* variable font data */ 1570#ifdef ROTATE 1571 for (i=0; i<pf->size; ++i) 1572 { 1573 bitmap_t* bits; 1574 int width = pf->width ? pf->width[i] : pf->maxwidth; 1575 int size; 1576 int char_code = pf->firstchar + i; 1577 unsigned char bytemap[ROTATION_BUF_SIZE]; 1578 1579 /* Skip missing glyphs */ 1580 if (pf->offset && (pf->offset[i] == -1)) 1581 continue; 1582 1583 bits = pf->bits + (pf->offset? (int)pf->offset[i]: (pf->height * i)); 1584 1585 size = rotleft(bytemap, sizeof(bytemap), bits, width, pf->height, char_code); 1586 if (size < 0) { 1587 return -1; 1588 } 1589 writestr(ofp, (char *)bytemap, size); 1590 1591 /* update offrot since bits are now in sorted order */ 1592 pf->offrot[i] = ofr; 1593 ofr += size; 1594 } 1595 1596 if ( pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS ) 1597 { 1598 /* bitmap offset is small enough, use unsigned short for offset */ 1599 if (ftell(ofp) & 1) 1600 writebyte(ofp, 0); /* pad to 16-bit boundary */ 1601 } 1602 else 1603 { 1604 /* bitmap offset is larger then 64K, use unsigned int for offset */ 1605 while (ftell(ofp) & 3) 1606 writebyte(ofp, 0); /* pad to 32-bit boundary */ 1607 } 1608 1609 if (pf->offset) 1610 { 1611 for (i=0; i<pf->size; ++i) 1612 { 1613 int offrot = pf->offrot[i]; 1614 if (pf->offset[i] == -1) { 1615 offrot = pf->offrot[pf->defaultchar - pf->firstchar]; 1616 } 1617 if ( pf->bits_size < MAX_FONTSIZE_FOR_16_BIT_OFFSETS ) 1618 writeshort(ofp, offrot); 1619 else 1620 writeint(ofp, offrot); 1621 } 1622 } 1623 1624 if (pf->width) 1625 for (i=0; i<pf->size; ++i) 1626 writebyte(ofp, pf->width[i]); 1627#else 1628 for (i=0; i<pf->bits_size; ++i) 1629 writeshort(ofp, pf->bits[i]); 1630 if (ftell(ofp) & 2) 1631 writeshort(ofp, 0); /* pad to 32-bit boundary */ 1632 1633 if (pf->offset) 1634 for (i=0; i<pf->size; ++i) { 1635 int offset = pf->offset[i]; 1636 if (offset == -1) { 1637 offset = pf->offset[pf->defaultchar - pf->firstchar]; 1638 } 1639 writeint(ofp, offset); 1640 } 1641 1642 if (pf->width) 1643 for (i=0; i<pf->size; ++i) 1644 writebyte(ofp, pf->width[i]); 1645#endif 1646 fclose(ofp); 1647 return 0; 1648}