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

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