1
0
Fork 0
forked from len0rd/rockbox

Introduced new options for convbdf that specify how the ascent/descent is allowed to grow to avoid glyph clipping.

The syntax is (for ascent, descent is similar): N[%][!]. E.g. -a3 allows ascent to become 3 pixels greater; -a3! forces ascent to become 3 px greater; -a20% allows ascent to grow 20% from what is specified in the font.
By default, ascent/descent are not allowed to grow.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20239 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Alexander Levin 2009-03-08 16:23:14 +00:00
parent 66cf3a3329
commit bded5db2d9

View file

@ -54,6 +54,9 @@ struct font {
/* unused by runtime system, read in by convbdf */ /* unused by runtime system, read in by convbdf */
int nchars; /* number of different glyphs */ int nchars; /* number of different glyphs */
int nchars_declared; /* number of glyphs as declared in the header */
int ascent_declared; /* ascent as declared in the header */
int descent_declared; /* descent as declared in the header */
unsigned int* offrot; /* offsets into rotated bitmap data */ unsigned int* offrot; /* offsets into rotated bitmap data */
char* name; /* font name */ char* name; /* font name */
char* facename; /* facename of font */ char* facename; /* facename of font */
@ -70,6 +73,13 @@ struct font {
}; };
/* END font.h*/ /* END font.h*/
/* Description of how the ascent/descent is allowed to grow */
struct stretch {
int value; /* The delta value (in pixels or percents) */
int percent; /* Is the value in percents (true) or pixels (false)? */
int force; /* MUST the value be set (true) or is it just a max (false) */
};
#define isprefix(buf,str) (!strncmp(buf, str, strlen(str))) #define isprefix(buf,str) (!strncmp(buf, str, strlen(str)))
#define strequal(s1,s2) (!strcmp(s1, s2)) #define strequal(s1,s2) (!strcmp(s1, s2))
@ -78,14 +88,17 @@ struct font {
/* Depending on the verbosity level some warnings are printed or not */ /* Depending on the verbosity level some warnings are printed or not */
int verbosity_level = 0; int verbosity_level = 0;
int trace = 0;
/* Prints a warning of the specified verbosity level. It will only be /* Prints a warning of the specified verbosity level. It will only be
really printed if the level is >= the level set in the settings */ really printed if the level is >= the level set in the settings */
void print_warning(int level, const char *fmt, ...); void print_warning(int level, const char *fmt, ...);
void print_error(const char *fmt, ...); void print_error(const char *fmt, ...);
void print_info(const char *fmt, ...); void print_info(const char *fmt, ...);
#define VL_CLIP 1 /* Verbosity level for clip related warnings */ void print_trace(const char *fmt, ...);
#define VL_MIS 1 /* Verbosity level for other warnings */ #define VL_CLIP_FONT 1 /* Verbosity level for clip related warnings at font level */
#define VL_CLIP_CHAR 2 /* Verbosity level for clip related warnings at char level */
#define VL_MISC 1 /* Verbosity level for other warnings */
int gen_c = 0; int gen_c = 0;
int gen_h = 0; int gen_h = 0;
@ -96,6 +109,10 @@ int limit_char = 65535;
int oflag = 0; int oflag = 0;
char outfile[256]; char outfile[256];
struct stretch stretch_ascent = { 0, 0, 1 }; /* Don't allow ascent to grow by default */
struct stretch stretch_descent = { 0, 0, 1 }; /* Don't allow descent to grow by default */
void usage(void); void usage(void);
void getopts(int *pac, char ***pav); void getopts(int *pac, char ***pav);
int convbdf(char *path); int convbdf(char *path);
@ -104,9 +121,20 @@ void free_font(struct font* pf);
struct font* bdf_read_font(char *path); struct font* bdf_read_font(char *path);
int bdf_read_header(FILE *fp, struct font* pf); int bdf_read_header(FILE *fp, struct font* pf);
int bdf_read_bitmaps(FILE *fp, struct font* pf); int bdf_read_bitmaps(FILE *fp, struct font* pf);
/*
Counts the glyphs and determines the max dimensions of glyphs
(fills the fields nchars, maxwidth, max_over_ascent, max_over_descent).
Returns 0 on failure or not-0 on success.
*/
int bdf_analyze_font(FILE *fp, struct font* pf);
void bdf_correct_bbx(int *width, int *bbx); /* Corrects bbx and width if bbx<0 */
/* Corrects the ascent and returns the new value (value to use) */
int adjust_ascent(int ascent, int overflow, struct stretch *stretch);
char * bdf_getline(FILE *fp, char *buf, int len); char * bdf_getline(FILE *fp, char *buf, int len);
bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2); bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2);
void bitmap_buf_alloc(struct font* pf);
int gen_c_source(struct font* pf, char *path); int gen_c_source(struct font* pf, char *path);
int gen_h_header(struct font* pf, char *path); int gen_h_header(struct font* pf, char *path);
@ -115,20 +143,53 @@ int gen_fnt_file(struct font* pf, char *path);
void void
usage(void) usage(void)
{ {
char help[] = { /* We use string array because some C compilers issue warnings about too long strings */
"Usage: convbdf [options] [input-files]\n" char *help[] = {
" convbdf [options] [-o output-file] [single-input-file]\n" "Usage: convbdf [options] [input-files]\n",
"Options:\n" " convbdf [options] [-o output-file] [single-input-file]\n",
" -c Convert .bdf to .c source file\n" "Options:\n",
" -h Convert .bdf to .h header file (to create sysfont.h)\n" " -c Convert .bdf to .c source file\n",
" -f Convert .bdf to .fnt font file\n" " -h Convert .bdf to .h header file (to create sysfont.h)\n",
" -s N Start output at character encodings >= N\n" " -f Convert .bdf to .fnt font file\n",
" -l N Limit output to character encodings <= N\n" " -s N Start output at character encodings >= N\n",
" -n Don't generate bitmaps as comments in .c file\n" " -l N Limit output to character encodings <= N\n",
" -v N Verbosity level: 0=quite quiet, 1=more verbose, 2=even more, etc.\n" " -n Don't generate bitmaps as comments in .c file\n",
" -a N[%][!] Allow the ascent to grow N pixels/% to avoid glyph clipping\n",
" -d N[%][!] Allow the descent to grow N pixels/% to avoid glyph clipping\n",
" -v N Verbosity level: 0=quite quiet, 1=more verbose, 2=even more, etc.\n",
" -t Print internal tracing messages\n",
NULL /* Must be the last element in the array */
}; };
print_info("%s", help); char **p = help;
while (*p != NULL)
print_info("%s", *(p++));
}
void parse_ascent_opt(char *val, struct stretch *opt) {
char buf[256];
char *p;
strcpy(buf, val);
opt->force = 0;
opt->percent = 0;
p = buf + strlen(buf);
while (p > buf) {
p--;
if (*p == '%') {
opt->percent = 1;
*p = '\0';
}
else if (*p == '!') {
opt->force = 1;
*p = '\0';
}
else {
break;
}
}
opt->value = atoi(buf);
} }
/* parse command line options*/ /* parse command line options*/
@ -199,6 +260,30 @@ void getopts(int *pac, char ***pav)
start_char = atoi(av[0]); start_char = atoi(av[0]);
} }
break; break;
case 'a': /* ascent growth */
if (*p) {
parse_ascent_opt(p, &stretch_ascent);
while (*p && *p != ' ')
p++;
}
else {
av++; ac--;
if (ac > 0)
parse_ascent_opt(av[0], &stretch_ascent);
}
break;
case 'd': /* descent growth */
if (*p) {
parse_ascent_opt(p, &stretch_descent);
while (*p && *p != ' ')
p++;
}
else {
av++; ac--;
if (ac > 0)
parse_ascent_opt(av[0], &stretch_descent);
}
break;
case 'v': /* verbosity */ case 'v': /* verbosity */
if (*p) { if (*p) {
verbosity_level = atoi(p); verbosity_level = atoi(p);
@ -211,6 +296,9 @@ void getopts(int *pac, char ***pav)
verbosity_level = atoi(av[0]); verbosity_level = atoi(av[0]);
} }
break; break;
case 't': /* tracing */
trace = 1;
break;
default: default:
print_info("Unknown option ignored: %c\n", *(p-1)); print_info("Unknown option ignored: %c\n", *(p-1));
} }
@ -230,6 +318,16 @@ void print_warning(int level, const char *fmt, ...) {
} }
} }
void print_trace(const char *fmt, ...) {
if (trace) {
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "TRACE: ");
vfprintf(stderr, fmt, ap);
va_end(ap);
}
}
void print_error(const char *fmt, ...) { void print_error(const char *fmt, ...) {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
@ -374,21 +472,64 @@ struct font* bdf_read_font(char *path)
print_error("Error reading font header\n"); print_error("Error reading font header\n");
goto errout; goto errout;
} }
print_trace("Read font header, nchars_decl=%d\n", pf->nchars_declared);
if (!bdf_analyze_font(fp, pf)) {
print_error("Error analyzing the font\n");
goto errout;
}
print_trace("Analyzed font, nchars=%d, maxwidth=%d, asc_over=%d, desc_over=%d\n",
pf->nchars, pf->maxwidth, pf->max_over_ascent, pf->max_over_descent);
if (pf->nchars != pf->nchars_declared) {
print_warning(VL_MISC, "The declared number of chars (%d) "
"does not match the real number (%d)\n",
pf->nchars_declared, pf->nchars);
}
/* Correct ascent/descent if necessary */
pf->ascent = adjust_ascent(pf->ascent_declared, pf->max_over_ascent, &stretch_ascent);
if (pf->ascent != pf->ascent_declared) {
print_info("Font ascent has been changed from %d to %d\n",
pf->ascent_declared, pf->ascent);
}
pf->descent = adjust_ascent(pf->descent, pf->max_over_descent, &stretch_descent);
if (pf->descent != pf->descent_declared) {
print_info("Font descent has been changed from %d to %d\n",
pf->descent_declared, pf->descent);
}
pf->height = pf->ascent + pf->descent;
if (pf->height != pf->ascent_declared + pf->descent_declared) {
print_warning(VL_CLIP_FONT, "Generated font's height: %d\n", pf->height);
}
/* Alocate memory */
pf->bits_size = pf->size * BITMAP_WORDS(pf->maxwidth) * pf->height;
pf->bits = (bitmap_t *)malloc(pf->bits_size * sizeof(bitmap_t));
pf->offset = (int *)malloc(pf->size * sizeof(int));
pf->offrot = (unsigned int *)malloc(pf->size * sizeof(unsigned int));
pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char));
if (!pf->bits || !pf->offset || !pf->offrot || !pf->width) {
print_error("no memory for font load\n");
goto errout;
}
pf->max_over_ascent = pf->max_over_descent = 0;
pf->num_clipped_ascent = pf->num_clipped_descent = pf->num_clipped = 0; pf->num_clipped_ascent = pf->num_clipped_descent = pf->num_clipped = 0;
pf->max_over_ascent = pf->max_over_descent = 0;
if (!bdf_read_bitmaps(fp, pf)) { if (!bdf_read_bitmaps(fp, pf)) {
print_error("Error reading font bitmaps\n"); print_error("Error reading font bitmaps\n");
goto errout; goto errout;
} }
print_trace("Read bitmaps\n");
if (pf->num_clipped > 0) { if (pf->num_clipped > 0) {
print_warning(VL_CLIP, "%d character(s) out of %d were clipped " print_warning(VL_CLIP_FONT, "%d character(s) out of %d were clipped "
"(%d at ascent, %d at descent)\n", "(%d at ascent, %d at descent)\n",
pf->num_clipped, pf->nchars, pf->num_clipped, pf->nchars,
pf->num_clipped_ascent, pf->num_clipped_descent); pf->num_clipped_ascent, pf->num_clipped_descent);
print_warning(VL_CLIP, "max overflows: %d pixel(s) at ascent, %d pixel(s) at descent\n", print_warning(VL_CLIP_FONT, "max overflows: %d pixel(s) at ascent, %d pixel(s) at descent\n",
pf->max_over_ascent, pf->max_over_descent); pf->max_over_ascent, pf->max_over_descent);
} }
@ -444,17 +585,19 @@ int bdf_read_header(FILE *fp, struct font* pf)
} }
} }
if (isprefix(buf, "FONT_DESCENT ")) { if (isprefix(buf, "FONT_DESCENT ")) {
if (sscanf(buf, "FONT_DESCENT %d", &pf->descent) != 1) { if (sscanf(buf, "FONT_DESCENT %d", &pf->descent_declared) != 1) {
print_error("bad 'FONT_DESCENT'\n"); print_error("bad 'FONT_DESCENT'\n");
return 0; return 0;
} }
pf->descent = pf->descent_declared; /* For now */
continue; continue;
} }
if (isprefix(buf, "FONT_ASCENT ")) { if (isprefix(buf, "FONT_ASCENT ")) {
if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent) != 1) { if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent_declared) != 1) {
print_error("bad 'FONT_ASCENT'\n"); print_error("bad 'FONT_ASCENT'\n");
return 0; return 0;
} }
pf->ascent = pf->ascent_declared; /* For now */
continue; continue;
} }
if (isprefix(buf, "FONTBOUNDINGBOX ")) { if (isprefix(buf, "FONTBOUNDINGBOX ")) {
@ -466,7 +609,7 @@ int bdf_read_header(FILE *fp, struct font* pf)
continue; continue;
} }
if (isprefix(buf, "CHARS ")) { if (isprefix(buf, "CHARS ")) {
if (sscanf(buf, "CHARS %d", &pf->nchars) != 1) { if (sscanf(buf, "CHARS %d", &pf->nchars_declared) != 1) {
print_error("bad 'CHARS'\n"); print_error("bad 'CHARS'\n");
return 0; return 0;
} }
@ -516,20 +659,6 @@ int bdf_read_header(FILE *fp, struct font* pf)
pf->firstchar = firstchar; pf->firstchar = firstchar;
pf->size = lastchar - firstchar + 1; pf->size = lastchar - firstchar + 1;
/* use the font boundingbox to get initial maxwidth */
/*maxwidth = pf->fbbw - pf->fbbx;*/
pf->maxwidth = pf->fbbw;
bitmap_buf_alloc(pf); /* Allocate bitmaps */
pf->offset = (int *)malloc(pf->size * sizeof(int));
pf->offrot = (unsigned int *)malloc(pf->size * sizeof(unsigned int));
pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char));
if (!pf->bits || !pf->offset || !pf->offrot || !pf->width) {
print_error("no memory for font load\n");
return 0;
}
return 1; return 1;
} }
@ -610,15 +739,7 @@ int bdf_read_bitmaps(FILE *fp, struct font* pf)
pf->offrot[encoding-pf->firstchar] = ofr; pf->offrot[encoding-pf->firstchar] = ofr;
/* calc char width */ /* calc char width */
if (bbx < 0) { bdf_correct_bbx(&width, &bbx);
/* Rockbox can't render overlapping glyphs */
width -= bbx;
bbx = 0;
}
if (width > pf->maxwidth) {
pf->maxwidth = width;
bitmap_buf_alloc(pf); /* Re-allocate bitmaps since the maxwidth has grown */
}
pf->width[encoding-pf->firstchar] = width; pf->width[encoding-pf->firstchar] = width;
ch_bitmap = pf->bits + ofs; ch_bitmap = pf->bits + ofs;
@ -638,7 +759,7 @@ int bdf_read_bitmaps(FILE *fp, struct font* pf)
pf->max_over_ascent = overflow_asc; pf->max_over_ascent = overflow_asc;
} }
bbh = MAX(bbh - overflow_asc, 0); /* Clipped -> decrease the height */ bbh = MAX(bbh - overflow_asc, 0); /* Clipped -> decrease the height */
print_warning(VL_CLIP, "character %d goes %d pixel(s)" print_warning(VL_CLIP_CHAR, "character %d goes %d pixel(s)"
" beyond the font's ascent, it will be clipped\n", " beyond the font's ascent, it will be clipped\n",
encoding, overflow_asc); encoding, overflow_asc);
} }
@ -650,7 +771,7 @@ int bdf_read_bitmaps(FILE *fp, struct font* pf)
} }
bby += overflow_desc; bby += overflow_desc;
bbh = MAX(bbh - overflow_desc, 0); /* Clipped -> decrease the height */ bbh = MAX(bbh - overflow_desc, 0); /* Clipped -> decrease the height */
print_warning(VL_CLIP, "character %d goes %d pixel(s)" print_warning(VL_CLIP_CHAR, "character %d goes %d pixel(s)"
" beyond the font's descent, it will be clipped\n", " beyond the font's descent, it will be clipped\n",
encoding, overflow_desc); encoding, overflow_desc);
} }
@ -797,16 +918,125 @@ char *bdf_getline(FILE *fp, char *buf, int len)
return buf; return buf;
} }
/* void bdf_correct_bbx(int *width, int *bbx) {
Calculates the necessary size of the bit buffer to hold all the if (*bbx < 0) {
bitmaps for the glyphs in the font. Shoud be called every time /* Rockbox can't render overlapping glyphs */
the max width of the font grows. Font height, the max width and *width -= *bbx;
the number of chars in the font must have been already set. *bbx = 0;
*/ }
void bitmap_buf_alloc(struct font* pf) }
{
pf->bits_size = pf->size * BITMAP_WORDS(pf->maxwidth) * pf->height; int bdf_analyze_font(FILE *fp, struct font* pf) {
pf->bits = (bitmap_t *)realloc(pf->bits, pf->bits_size * sizeof(bitmap_t)); char buf[256];
int encoding;
int width, bbw, bbh, bbx, bby, overflow;
int read_enc = 0, read_width = 0, read_bbx = 0, read_endchar = 1;
int ignore_char = 0;
/* reset file pointer */
fseek(fp, 0L, SEEK_SET);
pf->maxwidth = 0;
pf->nchars = 0;
pf->max_over_ascent = pf->max_over_descent = 0;
for (;;) {
if (!bdf_getline(fp, buf, sizeof(buf))) {
print_error("EOF on file\n");
return 0;
}
if (isprefix(buf, "ENDFONT")) {
if (!read_endchar) {
print_error("No terminating ENDCHAR for character %d\n", encoding);
return 0;
}
break;
}
if (isprefix(buf, "STARTCHAR")) {
print_trace("Read STARTCHAR, nchars=%d, read_endchar=%d\n", pf->nchars, read_endchar);
if (!read_endchar) {
print_error("No terminating ENDCHAR for character %d\n", encoding);
return 0;
}
read_enc = read_width = read_bbx = read_endchar = 0;
continue;
}
if (isprefix(buf, "ENDCHAR")) {
if (!read_enc) {
print_error("ENCODING is not specified\n");
return 0;
}
ignore_char = (encoding < start_char || encoding > limit_char);
if (!ignore_char) {
if (!read_width || !read_bbx) {
print_error("WIDTH or BBX is not specified for character %d\n",
encoding);
}
bdf_correct_bbx(&width, &bbx);
if (width > pf->maxwidth) {
pf->maxwidth = width;
}
overflow = bby + bbh - pf->ascent;
if (overflow > pf->max_over_ascent) {
pf->max_over_ascent = overflow;
}
overflow = -bby - pf->descent;
if (overflow > pf->max_over_descent) {
pf->max_over_descent = overflow;
}
}
pf->nchars++;
read_endchar = 1;
continue;
}
if (isprefix(buf, "ENCODING ")) {
if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
print_error("bad 'ENCODING': '%s'\n", buf);
return 0;
}
read_enc = 1;
continue;
}
if (isprefix(buf, "DWIDTH ")) {
if (sscanf(buf, "DWIDTH %d", &width) != 1) {
print_error("bad 'DWIDTH': '%s'\n", buf);
return 0;
}
/* use font boundingbox width if DWIDTH <= 0 */
if (width < 0) {
print_error("Negative char width: %d\n", width);
return 0;
}
read_width = 1;
}
if (isprefix(buf, "BBX ")) {
if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) {
print_error("bad 'BBX': '%s'\n", buf);
return 0;
}
read_bbx = 1;
continue;
}
}
return 1;
}
int adjust_ascent(int ascent, int overflow, struct stretch *stretch) {
int result;
int px = stretch->value;
if (stretch->percent) {
px = ascent * px / 100;
}
if (stretch->force) {
result = ascent + px;
}
else {
result = ascent + MIN(overflow, px);
}
result = MAX(result, 0);
return result;
} }