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 */
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 */
char* name; /* font name */
char* facename; /* facename of font */
@ -70,6 +73,13 @@ struct font {
};
/* 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 strequal(s1,s2) (!strcmp(s1, s2))
@ -78,14 +88,17 @@ struct font {
/* Depending on the verbosity level some warnings are printed or not */
int verbosity_level = 0;
int trace = 0;
/* Prints a warning of the specified verbosity level. It will only be
really printed if the level is >= the level set in the settings */
void print_warning(int level, const char *fmt, ...);
void print_error(const char *fmt, ...);
void print_info(const char *fmt, ...);
#define VL_CLIP 1 /* Verbosity level for clip related warnings */
#define VL_MIS 1 /* Verbosity level for other warnings */
void print_trace(const char *fmt, ...);
#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_h = 0;
@ -96,6 +109,10 @@ int limit_char = 65535;
int oflag = 0;
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 getopts(int *pac, char ***pav);
int convbdf(char *path);
@ -104,9 +121,20 @@ void free_font(struct font* pf);
struct font* bdf_read_font(char *path);
int bdf_read_header(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);
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_h_header(struct font* pf, char *path);
@ -115,20 +143,53 @@ int gen_fnt_file(struct font* pf, char *path);
void
usage(void)
{
char help[] = {
"Usage: convbdf [options] [input-files]\n"
" convbdf [options] [-o output-file] [single-input-file]\n"
"Options:\n"
" -c Convert .bdf to .c source file\n"
" -h Convert .bdf to .h header file (to create sysfont.h)\n"
" -f Convert .bdf to .fnt font file\n"
" -s N Start output at character encodings >= N\n"
" -l N Limit output to character encodings <= N\n"
" -n Don't generate bitmaps as comments in .c file\n"
" -v N Verbosity level: 0=quite quiet, 1=more verbose, 2=even more, etc.\n"
/* We use string array because some C compilers issue warnings about too long strings */
char *help[] = {
"Usage: convbdf [options] [input-files]\n",
" convbdf [options] [-o output-file] [single-input-file]\n",
"Options:\n",
" -c Convert .bdf to .c source file\n",
" -h Convert .bdf to .h header file (to create sysfont.h)\n",
" -f Convert .bdf to .fnt font file\n",
" -s N Start output at character encodings >= N\n",
" -l N Limit output to character encodings <= N\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*/
@ -199,6 +260,30 @@ void getopts(int *pac, char ***pav)
start_char = atoi(av[0]);
}
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 */
if (*p) {
verbosity_level = atoi(p);
@ -211,6 +296,9 @@ void getopts(int *pac, char ***pav)
verbosity_level = atoi(av[0]);
}
break;
case 't': /* tracing */
trace = 1;
break;
default:
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, ...) {
va_list ap;
va_start(ap, fmt);
@ -374,21 +472,64 @@ struct font* bdf_read_font(char *path)
print_error("Error reading font header\n");
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->max_over_ascent = pf->max_over_descent = 0;
if (!bdf_read_bitmaps(fp, pf)) {
print_error("Error reading font bitmaps\n");
goto errout;
}
print_trace("Read bitmaps\n");
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",
pf->num_clipped, pf->nchars,
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);
}
@ -444,17 +585,19 @@ int bdf_read_header(FILE *fp, struct font* pf)
}
}
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");
return 0;
}
pf->descent = pf->descent_declared; /* For now */
continue;
}
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");
return 0;
}
pf->ascent = pf->ascent_declared; /* For now */
continue;
}
if (isprefix(buf, "FONTBOUNDINGBOX ")) {
@ -466,7 +609,7 @@ int bdf_read_header(FILE *fp, struct font* pf)
continue;
}
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");
return 0;
}
@ -516,20 +659,6 @@ int bdf_read_header(FILE *fp, struct font* pf)
pf->firstchar = firstchar;
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;
}
@ -610,15 +739,7 @@ int bdf_read_bitmaps(FILE *fp, struct font* pf)
pf->offrot[encoding-pf->firstchar] = ofr;
/* calc char width */
if (bbx < 0) {
/* 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 */
}
bdf_correct_bbx(&width, &bbx);
pf->width[encoding-pf->firstchar] = width;
ch_bitmap = pf->bits + ofs;
@ -638,7 +759,7 @@ int bdf_read_bitmaps(FILE *fp, struct font* pf)
pf->max_over_ascent = overflow_asc;
}
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",
encoding, overflow_asc);
}
@ -650,7 +771,7 @@ int bdf_read_bitmaps(FILE *fp, struct font* pf)
}
bby += overflow_desc;
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",
encoding, overflow_desc);
}
@ -797,16 +918,125 @@ char *bdf_getline(FILE *fp, char *buf, int len)
return buf;
}
/*
Calculates the necessary size of the bit buffer to hold all the
bitmaps for the glyphs in the font. Shoud be called every time
the max width of the font grows. Font height, the max width and
the number of chars in the font must have been already set.
*/
void bitmap_buf_alloc(struct font* pf)
{
pf->bits_size = pf->size * BITMAP_WORDS(pf->maxwidth) * pf->height;
pf->bits = (bitmap_t *)realloc(pf->bits, pf->bits_size * sizeof(bitmap_t));
void bdf_correct_bbx(int *width, int *bbx) {
if (*bbx < 0) {
/* Rockbox can't render overlapping glyphs */
*width -= *bbx;
*bbx = 0;
}
}
int bdf_analyze_font(FILE *fp, struct font* pf) {
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;
}