source: libcaca/trunk/tools/makefont.c @ 914

Last change on this file since 914 was 914, checked in by Sam Hocevar, 14 years ago
  • Added Unicode range U+2200 - U+22FF (Mathematical Operators) to the built-in font so that we now cover all of CP437.
  • Property svn:keywords set to Id
File size: 9.0 KB
Line 
1/*
2 *  makefont       create libcaca font data
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: makefont.c 914 2006-04-26 15:21:28Z sam $
7 *
8 *  This program is free software; you can redistribute it and/or
9 *  modify it under the terms of the Do What The Fuck You Want To
10 *  Public License, Version 2, as published by Sam Hocevar. See
11 *  http://sam.zoy.org/wtfpl/COPYING for more details.
12 *
13 * Usage:
14 *   makefont <prefix> <font> <dpi> <bpp>
15 */
16
17#include "config.h"
18#include "common.h"
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <stdint.h>
23
24#if defined(HAVE_ARPA_INET_H)
25#   include <arpa/inet.h>
26#elif defined(HAVE_NETINET_IN_H)
27#   include <netinet/in.h>
28#endif
29
30#include <pango/pango.h>
31#include <pango/pangoft2.h>
32
33/* This list is built so that it includes all of ASCII, Latin-1, CP-437,
34 * and the UTF-8 glyphs necessary for canvas rotation and mirroring. */
35static int const blocklist[] =
36{
37    0x0000, 0x0080, /* Basic latin: A, B, C, a, b, c */
38    0x0080, 0x0100, /* Latin-1 Supplement: Ä, Ç, å, ß */
39    0x0100, 0x0180, /* Latin Extended-A: Ā č Ō œ */
40    0x0180, 0x0250, /* Latin Extended-B: Ǝ Ƹ */
41    0x0250, 0x02b0, /* IPA Extensions: ɐ ɔ ɘ ʌ ʍ */
42    0x0370, 0x0400, /* Greek and Coptic: Λ α β */
43    0x0400, 0x0500, /* Cyrillic: И Я */
44    0x2000, 0x2070, /* General Punctuation: ‘’ “” */
45#if 0
46    0x2100, 0x2150, /* Letterlike Symbols: Ⅎ */
47#endif
48    0x2200, 0x2300, /* Mathematical Operators: √ ∞ ∙ */
49    0x2300, 0x2400, /* Miscellaneous Technical: ⌐ ⌂ ⌠ ⌡ */
50    0x2500, 0x2580, /* Box Drawing: ═ ║ ╗ ╔ ╩ */
51    0x2580, 0x25a0, /* Block Elements: ▛ ▞ ░ ▒ ▓ */
52    0, 0
53};
54
55static int printf_hex(char const *, uint8_t *, int);
56static int printf_u32(char const *, uint32_t);
57static int printf_u16(char const *, uint16_t);
58
59int main(int argc, char *argv[])
60{
61    PangoContext *cx;
62    PangoFontDescription *fd;
63    PangoFontMap *fm;
64    PangoLayout *l;
65    PangoRectangle r;
66
67    FT_Bitmap img;
68    int width, height, b, i, n, blocks, glyphs;
69    unsigned int glyph_size, control_size, data_size;
70    uint8_t *glyph_data;
71
72    unsigned int bpp, dpi;
73    char const *prefix, *font;
74
75    if(argc != 5)
76    {
77        fprintf(stderr, "%s: wrong argument count\n", argv[0]);
78        fprintf(stderr, "usage: %s <prefix> <font> <dpi> <bpp>\n", argv[0]);
79        fprintf(stderr, "eg: %s monospace9 \"Monospace 9\" 96 4\n", argv[0]);
80        return -1;
81    }
82
83    prefix = argv[1];
84    font = argv[2];
85    dpi = atoi(argv[3]);
86    bpp = atoi(argv[4]);
87
88    if(dpi == 0 || (bpp != 1 && bpp != 2 && bpp != 4 && bpp != 8))
89    {
90        fprintf(stderr, "%s: invalid argument\n", argv[0]);
91        return -1;
92    }
93
94    fprintf(stderr, "Font \"%s\", %i dpi, %i bpp\n", font, dpi, bpp);
95
96    /* Initialise Pango */
97    fm = pango_ft2_font_map_new();
98    pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fm), dpi, dpi);
99    cx = pango_ft2_font_map_create_context(PANGO_FT2_FONT_MAP(fm));
100
101    l = pango_layout_new(cx);
102    if(!l)
103    {
104        fprintf(stderr, "%s: unable to initialise pango\n", argv[0]);
105        g_object_unref(cx);
106        return -1;
107    }
108
109    fd = pango_font_description_from_string(font);
110    pango_layout_set_font_description(l, fd);
111    pango_font_description_free(fd);
112
113    /* Initialise our FreeType2 bitmap */
114    img.width = 256;
115    img.pitch = 256;
116    img.rows = 256;
117    img.buffer = malloc(256 * 256);
118    img.num_grays = 256;
119    img.pixel_mode = ft_pixel_mode_grays;
120
121    /* Test rendering so that we know the glyph width */
122    pango_layout_set_markup(l, "@", -1);
123    pango_layout_get_extents(l, NULL, &r);
124    width = PANGO_PIXELS(r.width);
125    height = PANGO_PIXELS(r.height);
126    glyph_size = ((width * height) + (8 / bpp) - 1) / (8 / bpp);
127    glyph_data = malloc(glyph_size);
128
129    /* Compute blocks and glyphs count */
130    blocks = 0;
131    glyphs = 0;
132    for(b = 0; blocklist[b + 1]; b += 2)
133    {
134        blocks++;
135        glyphs += blocklist[b + 1] - blocklist[b];
136    }
137
138    control_size = 24 + 12 * blocks + 8 * glyphs;
139    data_size = glyph_size * glyphs;
140
141    /* Let's go! */
142    printf("/* libcucul font file\n");
143    printf(" * \"%s\": %i dpi, %i bpp, %ix%i glyphs\n",
144           font, dpi, bpp, width, height);
145    printf(" * Automatically generated by tools/makefont.c:\n");
146    printf(" *   tools/makefont %s \"%s\" %i %i\n", prefix, font, dpi, bpp);
147    printf(" */\n");
148    printf("\n");
149
150    printf("static unsigned int const %s_size = %i;\n",
151           prefix, 8 + control_size + data_size);
152    printf("static unsigned char const %s_data[] =\n", prefix);
153
154    printf("/* file: */\n");
155    printf("\"CACA\" /* caca_header */\n");
156    printf("\"FONT\" /* caca_file_type */\n");
157    printf("\n");
158
159    printf("/* font_header: */\n");
160    printf_u32("\"%s\" /* control_size */\n", control_size);
161    printf_u32("\"%s\" /* data_size */\n", data_size);
162    printf_u16("\"%s\" /* version */\n", 1);
163    printf_u16("\"%s\" /* blocks */\n", blocks);
164    printf_u32("\"%s\" /* glyphs */\n", glyphs);
165    printf_u16("\"%s\" /* bpp */\n", bpp);
166    printf_u16("\"%s\" /* width */\n", width);
167    printf_u16("\"%s\" /* height */\n", height);
168    printf_u16("\"%s\" /* flags */\n", 1);
169    printf("\n");
170
171    printf("/* block_info: */\n");
172    n = 0;
173    for(b = 0; blocklist[b + 1]; b += 2)
174    {
175        printf_u32("\"%s", blocklist[b]);
176        printf_u32("%s", blocklist[b + 1]);
177        printf_u32("%s\"\n", n);
178        n += blocklist[b + 1] - blocklist[b];
179    }
180    printf("\n");
181
182    printf("/* glyph_info: */\n");
183    n = 0;
184    for(b = 0; blocklist[b + 1]; b += 2)
185    {
186        for(i = blocklist[b]; i < blocklist[b + 1]; i++)
187        {
188            printf_u16("\"%s", width);
189            printf_u16("%s", height);
190            printf_u32("%s\"\n", n * glyph_size);
191            n++;
192        }
193    }
194    printf("\n");
195
196    printf("/* font_data: */\n");
197    for(b = 0; blocklist[b + 1]; b += 2)
198    {
199        for(i = blocklist[b]; i < blocklist[b + 1]; i++)
200        {
201            unsigned int ch = i;
202            char buf[10], *parser;
203            int x, y, bytes;
204
205            if(ch < 0x80)
206            {
207                bytes = 1;
208                buf[0] = ch;
209                buf[1] = '\0';
210            }
211            else
212            {
213                static const unsigned char mark[7] =
214                {
215                    0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
216                };
217
218                /* FIXME: use libcucul instead of this shit */
219                bytes = (ch < 0x800) ? 2 : (ch < 0x10000) ? 3 : 4;
220                buf[bytes] = '\0';
221                parser = buf + bytes;
222
223                switch(bytes)
224                {
225                    case 4: *--parser = (ch | 0x80) & 0xbf; ch >>= 6;
226                    case 3: *--parser = (ch | 0x80) & 0xbf; ch >>= 6;
227                    case 2: *--parser = (ch | 0x80) & 0xbf; ch >>= 6;
228                }
229                *--parser = ch | mark[bytes];
230            }
231
232            /* Print glyph value in comment */
233            printf("/* U+%.04X: \"", i);
234
235            if(i < 0x20 || (i >= 0x80 && i <= 0xa0))
236                printf("\\x%.02x\" */", i);
237            else
238                printf("%s\" */ ", buf);
239
240            /* Render glyph on a bitmap */
241            pango_layout_set_text(l, buf, -1);
242            memset(glyph_data, 0, glyph_size);
243            memset(img.buffer, 0, img.pitch * height);
244            pango_ft2_render_layout(&img, l, 0, 0);
245
246            /* Write bitmap as an escaped C string */
247            n = 0;
248            for(y = 0; y < height; y++)
249            {
250                for(x = 0; x < width; x++)
251                {
252                    uint8_t pixel = img.buffer[y * img.pitch + x];
253
254                    pixel >>= (8 - bpp);
255                    glyph_data[n / 8] |= pixel << (8 - bpp - (n % 8));
256                    n += bpp;
257                }
258            }
259            printf_hex("\"%s\"\n", glyph_data, glyph_size);
260        }
261    }
262
263    printf(";\n");
264
265    free(img.buffer);
266    g_object_unref(l);
267    g_object_unref(cx);
268
269    return 0;
270}
271
272/*
273 * XXX: the following functions are local
274 */
275
276static int printf_u32(char const *fmt, uint32_t i)
277{
278    uint32_t ni = hton32(i);
279    return printf_hex(fmt, (uint8_t *)&ni, 4);
280}
281
282static int printf_u16(char const *fmt, uint16_t i)
283{
284    uint16_t ni = hton16(i);
285    return printf_hex(fmt, (uint8_t *)&ni, 2);
286}
287
288static int printf_hex(char const *fmt, uint8_t *data, int bytes)
289{
290    char buf[BUFSIZ];
291    char *parser = buf;
292    int rewind = 0; /* we use this variable to rewind 2 bytes after \000
293                     * was printed when the next char starts with "\", too. */
294
295    while(bytes--)
296    {
297        uint8_t ch = *data++;
298        if(ch == '\\' || ch == '"')
299        {
300            parser -= rewind;
301            parser += sprintf(parser, "\\%c", ch);
302            rewind = 0;
303        }
304        else if(ch >= 0x20 && ch < 0x7f)
305        {
306            parser += sprintf(parser, "%c", ch);
307            rewind = 0;
308        }
309        else
310        {
311            parser -= rewind;
312            parser += sprintf(parser, "\\%.03o", ch);
313            rewind = ch ? 0 : 2;
314        }
315    }
316
317    parser -= rewind;
318    parser[0] = '\0';
319
320    return printf(fmt, buf);
321}
322
Note: See TracBrowser for help on using the repository browser.