From 808a2705658a152265e28c1892b4e8232b5fad5c Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Tue, 26 Sep 2006 13:57:01 +0000 Subject: [PATCH] * Improved support for figlet fonts. We can now load them and print text. Still no smushing, no hard blanks, no line wrapping... --- src/figlet.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 2 deletions(-) diff --git a/src/figlet.c b/src/figlet.c index da24500..ff2049f 100644 --- a/src/figlet.c +++ b/src/figlet.c @@ -20,19 +20,181 @@ #if defined(HAVE_INTTYPES_H) # include #endif +#include +#include +#include #include #include "figlet.h" +struct figfont +{ + /* From the font format */ + unsigned char hardblank; + unsigned int height, baseline, max_length; + int old_layout; + unsigned int print_direction, full_layout, codetag_count; + + unsigned int glyphs; + cucul_canvas_t *image; + unsigned int *lookup; +}; + +static struct figfont *open_font(char const *); +static void free_font(struct figfont *); + cucul_canvas_t *render_figlet(uint32_t const *string, unsigned int length, char const *fontname) { cucul_canvas_t *cv; + struct figfont *font; + unsigned int x, i, c; + + font = open_font(fontname); + + cv = cucul_create_canvas(length * font->max_length, font->height); + + for(x = 0, i = 0; i < length; i++) + { + for(c = 0; c < font->glyphs; c++) + if(font->lookup[c * 2] == string[i]) + break; + + if(c == font->glyphs) + continue; + cucul_blit(cv, x, - (int)(c * font->height), font->image, NULL); + x += font->lookup[c * 2 + 1]; + } + + free_font(font); - cv = cucul_create_canvas(3, 1); - cucul_putstr(cv, 0, 0, "LOL"); return cv; } +static struct figfont *open_font(char const *fontname) +{ + char *data = NULL; + char path[2048]; + struct figfont *font; + cucul_buffer_t *b; + FILE *f; + unsigned int i, j, size, comment_lines; + + /* Open font */ + snprintf(path, 2047, "/usr/share/figlet/%s.flf", fontname); + path[2047] = '\0'; + f = fopen(path, "r"); + if(!f) + { + fprintf(stderr, "font `%s' not found\n", path); + return NULL; + } + + font = malloc(sizeof(struct figfont)); + + /* Read header */ + font->print_direction = 0; + font->full_layout = 0; + font->codetag_count = 0; + if(fscanf(f, "flf2a%c %u %u %u %i %u %u %u %u\n", &font->hardblank, + &font->height, &font->baseline, &font->max_length, + &font->old_layout, &comment_lines, &font->print_direction, + &font->full_layout, &font->codetag_count) < 6) + { + fprintf(stderr, "font `%s' has invalid header\n", path); + free(font); + fclose(f); + return NULL; + } + + /* Skip comment lines */ + for(i = 0; i < comment_lines; i++) + { + fscanf(f, "%*[^\n]"); + fscanf(f, "%*c"); + } + + /* Read mandatory characters (32-127, 196, 214, 220, 228, 246, 252, 223) + * then read additional characters. */ + font->glyphs = 0; + font->lookup = NULL; + + for(i = 0, size = 0; !feof(f); font->glyphs++) + { + if((font->glyphs % 2048) == 0) + font->lookup = realloc(font->lookup, + (font->glyphs + 2048) * 2 * sizeof(int)); + + if(font->glyphs < 127 - 32) + { + font->lookup[font->glyphs * 2] = 32 + font->glyphs; + } + else if(font->glyphs < (127 - 32) + 7) + { + static int const tab[7] = { 196, 214, 220, 228, 246, 252, 223 }; + font->lookup[font->glyphs * 2] = tab[font->glyphs = (127 - 32)]; + } + else + { + fscanf(f, "%u %*[^\n]", &font->lookup[font->glyphs * 2]); + fscanf(f, "%*c"); + } + + font->lookup[font->glyphs * 2 + 1] = 0; + + for(j = 0; j < font->height; j++) + { + if(i + 2048 >= size) + data = realloc(data, size += 2048); + + fgets(data + i, 2048, f); + i = (uintptr_t)strchr(data + i, 0) - (uintptr_t)data; + } + } + + fclose(f); + + /* Import buffer into canvas */ + b = cucul_load_memory(data, i); + font->image = cucul_import_canvas(b, "ansi"); + cucul_free_buffer(b); + free(data); + + /* Remove EOL characters. For now we ignore hardblanks, don’t do any + * smushing, nor any kind of error checking. */ + for(j = 0; j < font->height * font->glyphs; j++) + { + unsigned long int ch, oldch = 0; + + for(i = font->max_length; i--;) + { + ch = cucul_getchar(font->image, i, j); + + if(ch == font->hardblank) + cucul_putchar(font->image, i, j, ' '); + else if(oldch && ch != oldch) + { + if(!font->lookup[j / font->height * 2 + 1]) + font->lookup[j / font->height * 2 + 1] = i + 1; + } + else if(oldch && ch == oldch) + cucul_putchar(font->image, i, j, ' '); + else if(ch != ' ') + { + oldch = ch; + cucul_putchar(font->image, i, j, ' '); + } + } + } + + return font; +} + +static void free_font(struct figfont *font) +{ + free(font->lookup); + free(font); +} +