diff --git a/configure.ac b/configure.ac index 1c37370..6456fe3 100644 --- a/configure.ac +++ b/configure.ac @@ -21,8 +21,10 @@ AC_C_INLINE AC_TYPE_SIGNAL dnl AC_PROG_EGREP only exists in autoconf 2.54+, so we use AC_EGREP_CPP right -dnl now otherwise it might be set in an obscure if statement. +dnl now otherwise it might be set in an obscure if statement. Same thing for +dnl PKG_PROG_PKG_CONFIG which needs to be called first. AC_EGREP_CPP(foo, foo) +PKG_PROG_PKG_CONFIG() dnl output driver features AC_ARG_ENABLE(slang, @@ -257,6 +259,12 @@ if test "${enable_imlib2}" != "no"; then fi AM_CONDITIONAL(USE_IMLIB2, test "${ac_cv_my_have_imlib2}" = "yes") +# Build development tools? +PANGOFT2="no" + PKG_CHECK_MODULES(pangoft2, pangoft2, + [PANGOFT2="yes"]) +AM_CONDITIONAL(USE_PANGO, test "${PANGO}" != "no") + # Build documentation? DOXYGEN="no" LATEX="no" diff --git a/tools/Makefile.am b/tools/Makefile.am index 4735dc9..19dd749 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -2,7 +2,16 @@ AM_CPPFLAGS = -I$(top_srcdir)/cucul -I$(top_srcdir)/caca -DDATADIR=\"$(pkgdatadir)\" -noinst_PROGRAMS = optipal +noinst_PROGRAMS = optipal $(pango_programs) optipal_SOURCES = optipal.c +makefont_SOURCES = makefont.c +makefont_CFLAGS = `pkg-config --cflags pangoft2` +makefont_LDFLAGS = `pkg-config --libs pangoft2` + +if USE_PANGO +pango_programs = makefont +else +pango_programs = +endif diff --git a/tools/makefont.c b/tools/makefont.c new file mode 100644 index 0000000..5791c4a --- /dev/null +++ b/tools/makefont.c @@ -0,0 +1,277 @@ +/* + * makefont create libcaca font data + * Copyright (c) 2006 Sam Hocevar + * All Rights Reserved + * + * $Id$ + * + * This program is free software; 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. + * + * Usage: + * makefont + */ + +#include +#include +#include + +#include + +#include +#include + +#define FONT "Monospace 9" +#define DPI 96 +#define BPP 8 + +static int const blocklist[] = +{ + 0x0000, 0x0080, /* Basic latin: A, B, C, a, img, c */ + 0x0080, 0x0100, /* Latin-1 Supplement: Ä, Ç, å, ß */ + 0x0100, 0x0180, /* Latin Extended-A: Ā č Ō œ */ + 0x0180, 0x0250, /* Latin Extended-B: Ǝ Ƹ */ + 0x0250, 0x02b0, /* IPA Extensions: ɐ ɔ ɘ ʌ ʍ */ + 0x0370, 0x0400, /* Greek and Coptic: Λ α β */ + 0x0400, 0x0500, /* Cyrillic: И Я */ + 0x2000, 0x2070, /* General Punctuation: ‘’ “” */ +#if 0 + 0x2100, 0x2150, /* Letterlike Symbols: Ⅎ */ +#endif + 0x2300, 0x2400, /* Miscellaneous Technical: ⌂ */ + 0x2500, 0x2580, /* Box Drawing: ═ ║ ╗ ╔ ╩ */ + 0x2580, 0x25a0, /* Block Elements: ▛ ▞ ░ ▒ ▓ */ + 0, 0 +}; + +static int printf_hex(char const *fmt, uint8_t *data, int bytes) +{ + char buf[BUFSIZ]; + char *parser = buf; + int rewind = 0; /* we use this variable to rewind 2 bytes after \000 + * was printed when the next char starts with "\", too. */ + + while(bytes--) + { + uint8_t c = *data++; + if(c == '\\' || c == '"') + { + parser -= rewind; + parser += sprintf(parser, "\\%c", c); + rewind = 0; + } + else if(c >= 0x20 && c < 0x7f) + { + parser += sprintf(parser, "%c", c); + rewind = 0; + } + else + { + parser -= rewind; + parser += sprintf(parser, "\\%.03o", c); + rewind = c ? 0 : 2; + } + } + + parser -= rewind; + parser[0] = '\0'; + + return printf(fmt, buf); +} + +static int printf_u32(char const *fmt, uint32_t i) +{ + uint32_t ni = htonl(i); + return printf_hex(fmt, (uint8_t *)&ni, 4); +} + +static int printf_u16(char const *fmt, uint16_t i) +{ + uint16_t ni = htons(i); + return printf_hex(fmt, (uint8_t *)&ni, 2); +} + +int main(void) +{ + PangoContext *cx; + PangoFontDescription *fd; + PangoFontMap *fm; + PangoLayout *l; + PangoRectangle r; + + FT_Bitmap img; + int width, height, b, i, n, blocks, glyphs, data_bytes; + uint8_t *glyph_data; + + /* Initialise Pango */ + fm = pango_ft2_font_map_new(); + pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fm), DPI, DPI); + cx = pango_ft2_font_map_create_context(PANGO_FT2_FONT_MAP(fm)); + + l = pango_layout_new(cx); + if(!l) + { + g_object_unref(cx); + return -1; + } + + fd = pango_font_description_from_string(FONT); + pango_layout_set_font_description(l, fd); + pango_font_description_free(fd); + + /* Initialise our FreeType2 bitmap */ + img.width = 256; + img.pitch = 256; + img.rows = 256; + img.buffer = malloc(256 * 256); + img.num_grays = 256; + img.pixel_mode = ft_pixel_mode_grays; + + /* Test rendering so that we know the glyph width */ + pango_layout_set_markup(l, "@", -1); + pango_layout_get_extents(l, NULL, &r); + width = PANGO_PIXELS(r.width); + height = PANGO_PIXELS(r.height); + data_bytes = ((width * height) + (8 / BPP) - 1) / (8 / BPP); + glyph_data = malloc(data_bytes); + + /* Compute blocks and glyphs count */ + blocks = 0; + glyphs = 0; + for(b = 0; blocklist[b + 1]; b += 2) + { + blocks++; + glyphs += blocklist[b + 1] - blocklist[b]; + } + + /* Let's go! */ + printf("/* libcucul font file\n"); + printf(" * \"%s\": %i dpi, %i bpp, %ix%i glyphs\n", + FONT, DPI, BPP, width, height); + printf(" * Automatically generated by tools/makefont.c */\n"); + printf("\n"); + + printf("/* file: */\n"); + printf("\"CACA\" /* caca_header */\n"); + printf("\"FONT\" /* caca_file_type */\n"); + printf("\n"); + + printf("/* font_header: */\n"); + printf_u32("\"%s\" /* header_size */\n", 24 + 12 * blocks + 8 * glyphs); + printf_u32("\"%s\" /* data_size */\n", data_bytes * glyphs); + printf_u16("\"%s\" /* version */\n", 1); + printf_u16("\"%s\" /* blocks */\n", blocks); + printf_u32("\"%s\" /* glyphs */\n", glyphs); + printf_u16("\"%s\" /* bpp */\n", BPP); + printf_u16("\"%s\" /* width */\n", width); + printf_u16("\"%s\" /* height */\n", height); + printf_u16("\"%s\" /* flags */\n", 1); + printf("\n"); + + printf("/* block_info: */\n"); + n = 0; + for(b = 0; blocklist[b + 1]; b += 2) + { + printf_u32("\"%s", blocklist[b]); + printf_u32("%s", blocklist[b + 1]); + printf_u32("%s\"\n", n); + n += blocklist[b + 1] - blocklist[b]; + } + printf("\n"); + + printf("/* glyph_info: */\n"); + n = 0; + for(b = 0; blocklist[b + 1]; b += 2) + { + for(i = blocklist[b]; i < blocklist[b + 1]; i++) + { + printf_u16("\"%s", width); + printf_u16("%s", height); + printf_u32("%s\"\n", n * data_bytes); + n++; + } + } + printf("\n"); + + printf("/* font_data: */\n"); + for(b = 0; blocklist[b + 1]; b += 2) + { + for(i = blocklist[b]; i < blocklist[b + 1]; i++) + { + unsigned int ch = i; + char buf[10], *parser; + int x, y, bytes; + + if(ch < 0x80) + { + bytes = 1; + buf[0] = ch; + buf[1] = '\0'; + } + else + { + static const unsigned char mark[7] = + { + 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC + }; + + /* FIXME: use libcucul instead of this shit */ + bytes = (ch < 0x800) ? 2 : (ch < 0x10000) ? 3 : 4; + buf[bytes] = '\0'; + parser = buf + bytes; + + switch(bytes) + { + case 4: *--parser = (ch | 0x80) & 0xbf; ch >>= 6; + case 3: *--parser = (ch | 0x80) & 0xbf; ch >>= 6; + case 2: *--parser = (ch | 0x80) & 0xbf; ch >>= 6; + } + *--parser = ch | mark[bytes]; + } + + /* Print glyph value in comment */ + printf("/* U+%.04X: \"", i); + + if(i < 0x20 || (i >= 0x80 && i <= 0xa0)) + printf("\\x%.02x\" (", i); + else + printf("%s\" (", buf); + + for(x = 0; x < bytes; x++) + printf("%s0x%.02X", x ? " " : "", (unsigned char)buf[x]); + + printf(") */\n"); + + /* Render glyph on a bitmap */ + pango_layout_set_text(l, buf, -1); + memset(glyph_data, 0, data_bytes); + memset(img.buffer, 0, img.pitch * height); + pango_ft2_render_layout(&img, l, 0, 0); + + /* Write bitmap as an escaped C string */ + n = 0; + for(y = 0; y < height; y++) + { + for(x = 0; x < width; x++) + { + uint8_t pixel = img.buffer[y * img.pitch + x]; + + pixel >>= (8 - BPP); + /* FIXME: BPP should appear here */ + glyph_data[n / 8] |= (pixel << (n % 8)); + n += BPP; + } + } + printf_hex("\"%s\"\n", glyph_data, data_bytes); + } + } + + free(img.buffer); + g_object_unref(l); + g_object_unref(cx); + + return 0; +} +