diff --git a/cucul/Makefile.am b/cucul/Makefile.am index 20d13ef..30ef40f 100644 --- a/cucul/Makefile.am +++ b/cucul/Makefile.am @@ -29,6 +29,7 @@ libcucul_la_SOURCES = \ import.c \ export.c \ file.c \ + figfont.c \ $(NULL) libcucul_la_DEPENDENCIES = \ mono9.data \ diff --git a/cucul/canvas.c b/cucul/canvas.c index e5b4ff7..c0e0277 100644 --- a/cucul/canvas.c +++ b/cucul/canvas.c @@ -490,7 +490,7 @@ int cucul_set_canvas_boundaries(cucul_canvas_t *cv, int x, int y, } free(cv->frames); - memcpy(cv, new, sizeof(cucul_canvas_t)); + cv->frames = new->frames; free(new); cucul_set_frame(cv, saved_f); diff --git a/cucul/cucul.c b/cucul/cucul.c index 91ccc0b..6ac58eb 100644 --- a/cucul/cucul.c +++ b/cucul/cucul.c @@ -85,6 +85,8 @@ cucul_canvas_t * cucul_create_canvas(unsigned int width, unsigned int height) _cucul_load_frame_info(cv); cucul_set_color_ansi(cv, CUCUL_DEFAULT, CUCUL_TRANSPARENT); + cv->ff = NULL; + if(cucul_resize(cv, width, height) < 0) { int saved_errno = geterrno(); @@ -306,6 +308,9 @@ int cucul_free_canvas(cucul_canvas_t *cv) free(cv->frames[f].name); } + if(cv->ff) + _cucul_free_figfont(cv->ff); + free(cv->frames); free(cv); diff --git a/cucul/cucul.h b/cucul/cucul.h index e2c30fd..629012c 100644 --- a/cucul/cucul.h +++ b/cucul/cucul.h @@ -280,6 +280,14 @@ __extern int cucul_render_canvas(cucul_canvas_t const *, cucul_font_t const *, __extern int cucul_free_font(cucul_font_t *); /* @} */ +/** \defgroup cucul_figfont libcucul FIGfont handling + * + * These functions provide FIGlet and TOIlet font handling routines. + * + * @{ */ +__extern int cucul_canvas_set_figfont(cucul_canvas_t *, char const *); +/* @} */ + /** \defgroup cucul_importexport libcucul importers/exporters from/to various * formats * diff --git a/cucul/cucul_internals.h b/cucul/cucul_internals.h index ed5210c..59be7a5 100644 --- a/cucul/cucul_internals.h +++ b/cucul/cucul_internals.h @@ -19,6 +19,8 @@ # include #endif +typedef struct cucul_figfont cucul_figfont_t; + struct cucul_frame { /* Frame size */ @@ -39,6 +41,9 @@ struct cucul_frame struct cucul_canvas { + /* XXX: look at cucul_set_canvas_boundaries() before adding anything + * to this structure. The function is quite hacky. */ + /* Frame information */ unsigned int frame, framecount; struct cucul_frame *frames; @@ -54,6 +59,9 @@ struct cucul_canvas uint32_t *chars; uint32_t *attrs; uint32_t curattr; + + /* FIGfont management */ + cucul_figfont_t *ff; }; struct cucul_buffer @@ -77,4 +85,8 @@ extern int _cucul_file_close(cucul_file_t *); extern int _cucul_file_eof(cucul_file_t *); extern char *_cucul_file_gets(char *, int, cucul_file_t *); +/* FIGfont functions */ +extern cucul_figfont_t * _cucul_open_figfont(char const *); +extern int _cucul_free_figfont(cucul_figfont_t *); + #endif /* __CUCUL_INTERNALS_H__ */ diff --git a/cucul/figfont.c b/cucul/figfont.c new file mode 100644 index 0000000..dc60a02 --- /dev/null +++ b/cucul/figfont.c @@ -0,0 +1,261 @@ +/* + * libcucul Canvas for ultrafast compositing of Unicode letters + * Copyright (c) 2006-2007 Sam Hocevar + * All Rights Reserved + * + * $Id$ + * + * This library is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/* + * This file contains FIGlet and TOIlet font handling functions. + */ + +#include "config.h" +#include "common.h" + +#if !defined(__KERNEL__) +# include +# include +# include +#endif + +#include "cucul.h" +#include "cucul_internals.h" + +struct cucul_figfont +{ + /* Used by the FIGlet driver */ + unsigned long int hardblank; + unsigned int height, baseline, max_length; + int old_layout; + unsigned int print_direction, full_layout, codetag_count; + unsigned int glyphs; + cucul_canvas_t *fontcv; + unsigned int *lookup; +}; + +int cucul_canvas_set_figfont(cucul_canvas_t *cv, char const *path) +{ + cucul_figfont_t *ff = NULL; + + if(path) + { + ff = _cucul_open_figfont(path); + if(!ff) + return -1; + } + + if(cv->ff) + _cucul_free_figfont(cv->ff); + + cv->ff = ff; + + return 0; +} + +#define STD_GLYPHS (127 - 32) +#define EXT_GLYPHS (STD_GLYPHS + 7) + +cucul_figfont_t * _cucul_open_figfont(char const *path) +{ + char altpath[2048]; + char buf[2048]; + char hardblank[10]; + cucul_figfont_t *ff; + char *data = NULL; + cucul_file_t *f; + unsigned int i, j, size, comment_lines; + + ff = malloc(sizeof(cucul_figfont_t)); + if(!ff) + { + seterrno(ENOMEM); + return NULL; + } + + /* Open font: if not found, try .tlf, then .flf */ + f = _cucul_file_open(path, "r"); + if(!f) + { + snprintf(altpath, 2047, "%s.tlf", path); + altpath[2047] = '\0'; + f = _cucul_file_open(altpath, "r"); + } + if(!f) + { + snprintf(altpath, 2047, "%s.flf", path); + altpath[2047] = '\0'; + f = _cucul_file_open(altpath, "r"); + } + if(!f) + { + free(ff); + seterrno(ENOENT); + return NULL; + } + + /* Read header */ + ff->print_direction = 0; + ff->full_layout = 0; + ff->codetag_count = 0; + _cucul_file_gets(buf, 2048, f); + if(sscanf(buf, "%*[ft]lf2a%6s %u %u %u %i %u %u %u %u\n", hardblank, + &ff->height, &ff->baseline, &ff->max_length, + &ff->old_layout, &comment_lines, &ff->print_direction, + &ff->full_layout, &ff->codetag_count) < 6) + { + debug("figfont error: `%s' has invalid header: %s", path, buf); + _cucul_file_close(f); + free(ff); + seterrno(EINVAL); + return NULL; + } + + if(ff->old_layout < -1 || ff->old_layout > 63 || ff->full_layout > 32767 + || ((ff->full_layout & 0x80) && (ff->full_layout & 0x3f) == 0 + && ff->old_layout)) + { + debug("figfont error: `%s' has invalid layout %i/%u", + path, ff->old_layout, ff->full_layout); + _cucul_file_close(f); + free(ff); + seterrno(EINVAL); + return NULL; + } + + ff->hardblank = cucul_utf8_to_utf32(hardblank, NULL); + + /* Skip comment lines */ + for(i = 0; i < comment_lines; i++) + _cucul_file_gets(buf, 2048, f); + + /* Read mandatory characters (32-127, 196, 214, 220, 228, 246, 252, 223) + * then read additional characters. */ + ff->glyphs = 0; + ff->lookup = NULL; + + for(i = 0, size = 0; !_cucul_file_eof(f); ff->glyphs++) + { + if((ff->glyphs % 2048) == 0) + ff->lookup = realloc(ff->lookup, + (ff->glyphs + 2048) * 2 * sizeof(int)); + + if(ff->glyphs < STD_GLYPHS) + { + ff->lookup[ff->glyphs * 2] = 32 + ff->glyphs; + } + else if(ff->glyphs < EXT_GLYPHS) + { + static int const tab[7] = { 196, 214, 220, 228, 246, 252, 223 }; + ff->lookup[ff->glyphs * 2] = tab[ff->glyphs - STD_GLYPHS]; + } + else + { + if(_cucul_file_gets(buf, 2048, f) == NULL) + break; + + /* Ignore blank lines, as in jacky.flf */ + if(buf[0] == '\n' || buf[0] == '\r') + continue; + + /* Ignore negative indices for now, as in ivrit.flf */ + if(buf[0] == '-') + { + for(j = 0; j < ff->height; j++) + _cucul_file_gets(buf, 2048, f); + continue; + } + + if(!buf[0] || buf[0] < '0' || buf[0] > '9') + { + debug("figfont error: glyph #%u in `%s'", ff->glyphs, path); + free(data); + free(ff->lookup); + free(ff); + seterrno(EINVAL); + return NULL; + } + + if(buf[1] == 'x') + sscanf(buf, "%x", &ff->lookup[ff->glyphs * 2]); + else + sscanf(buf, "%u", &ff->lookup[ff->glyphs * 2]); + } + + ff->lookup[ff->glyphs * 2 + 1] = 0; + + for(j = 0; j < ff->height; j++) + { + if(i + 2048 >= size) + data = realloc(data, size += 2048); + + _cucul_file_gets(data + i, 2048, f); + i = (uintptr_t)strchr(data + i, 0) - (uintptr_t)data; + } + } + + _cucul_file_close(f); + + if(ff->glyphs < EXT_GLYPHS) + { + debug("figfont error: only %u glyphs in `%s', expected at least %u", + ff->glyphs, path, EXT_GLYPHS); + free(data); + free(ff->lookup); + free(ff); + seterrno(EINVAL); + return NULL; + } + + /* Import buffer into canvas */ + ff->fontcv = cucul_create_canvas(0, 0); + cucul_import_memory(ff->fontcv, data, i, "utf8"); + 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 < ff->height * ff->glyphs; j++) + { + unsigned long int ch, oldch = 0; + + for(i = ff->max_length; i--;) + { + ch = cucul_get_char(ff->fontcv, i, j); + + /* Replace hardblanks with U+00A0 NO-BREAK SPACE */ + if(ch == ff->hardblank) + cucul_put_char(ff->fontcv, i, j, ch = 0xa0); + + if(oldch && ch != oldch) + { + if(!ff->lookup[j / ff->height * 2 + 1]) + ff->lookup[j / ff->height * 2 + 1] = i + 1; + } + else if(oldch && ch == oldch) + cucul_put_char(ff->fontcv, i, j, ' '); + else if(ch != ' ') + { + oldch = ch; + cucul_put_char(ff->fontcv, i, j, ' '); + } + } + } + + return ff; +} + +int _cucul_free_figfont(cucul_figfont_t *ff) +{ + cucul_free_canvas(ff->fontcv); + free(ff->lookup); + free(ff); + + return 0; +} + diff --git a/examples/.gitignore b/examples/.gitignore index a61c76b..620262e 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -6,6 +6,7 @@ demo0 dithering event export +figfont font font2tga frames diff --git a/examples/Makefile.am b/examples/Makefile.am index fafac97..3699ac5 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -2,7 +2,7 @@ AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/cucul -I$(top_srcdir)/caca -DDATADIR=\"$(pkgdatadir)\" -noinst_PROGRAMS = blit colors cucul demo demo0 dithering event export font font2tga frames fullwidth gamma hsv input spritedit swallow text transform truecolor unicode import +noinst_PROGRAMS = blit colors cucul demo demo0 dithering event export figfont font font2tga frames fullwidth gamma hsv input spritedit swallow text transform truecolor unicode import blit_SOURCES = blit.c blit_LDADD = ../caca/libcaca.la ../cucul/libcucul.la @@ -30,6 +30,9 @@ event_LDADD = ../caca/libcaca.la ../cucul/libcucul.la export_SOURCES = export.c export_LDADD = ../cucul/libcucul.la +figfont_SOURCES = figfont.c +figfont_LDADD = ../cucul/libcucul.la + font_SOURCES = font.c font_LDADD = ../caca/libcaca.la ../cucul/libcucul.la diff --git a/examples/figfont.c b/examples/figfont.c new file mode 100644 index 0000000..8ee269b --- /dev/null +++ b/examples/figfont.c @@ -0,0 +1,45 @@ +/* + * figfont libcucul FIGfont test program + * Copyright (c) 2007 Sam Hocevar + * All Rights Reserved + * + * $Id$ + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +#include "config.h" +#include "common.h" + +#if !defined(__KERNEL__) +# include +#endif + +#include "cucul.h" + +int main(int argc, char *argv[]) +{ + cucul_canvas_t *cv; + + if(argc < 2) + { + fprintf(stderr, "Too few arguments\n"); + return -1; + } + + cv = cucul_create_canvas(0, 0); + if(cucul_canvas_set_figfont(cv, argv[1])) + { + fprintf(stderr, "Could not open font\n"); + return -1; + } + + cucul_free_canvas(cv); + + return 0; +} +