* Improved support for figlet fonts. We can now load them and print text.

Still no smushing, no hard blanks, no line wrapping...
This commit is contained in:
Sam Hocevar 2006-09-26 13:57:01 +00:00 committed by sam
parent b3bc7d4270
commit 808a270565

View file

@ -20,19 +20,181 @@
#if defined(HAVE_INTTYPES_H)
# include <inttypes.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cucul.h>
#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, dont 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);
}