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

Last change on this file since 930 was 930, checked in by Sam Hocevar, 14 years ago
  • Hardcode a few CP437 glyphs in makefont.c because they don't look that good with Pango.
  • Property svn:keywords set to Id
File size: 11.1 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 930 2006-05-05 15:12:50Z 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 "cucul.h"
31#include "cucul_internals.h"
32
33#include <pango/pango.h>
34#include <pango/pangoft2.h>
35
36/* This list is built so that it includes all of ASCII, Latin-1, CP-437,
37 * and the UTF-8 glyphs necessary for canvas rotation and mirroring. */
38static int const blocklist[] =
39{
40    0x0000, 0x0080, /* Basic latin: A, B, C, a, b, c */
41    0x0080, 0x0100, /* Latin-1 Supplement: Ä, Ç, å, ß */
42    0x0100, 0x0180, /* Latin Extended-A: Ā č Ō œ */
43    0x0180, 0x0250, /* Latin Extended-B: Ǝ Ƹ */
44    0x0250, 0x02b0, /* IPA Extensions: ɐ ɔ ɘ ʌ ʍ */
45    0x0370, 0x0400, /* Greek and Coptic: Λ α β */
46    0x0400, 0x0500, /* Cyrillic: И Я */
47    0x2000, 0x2070, /* General Punctuation: ‘’ “” */
48#if 0
49    0x2100, 0x2150, /* Letterlike Symbols: Ⅎ */
50#endif
51    0x2200, 0x2300, /* Mathematical Operators: √ ∞ ∙ */
52    0x2300, 0x2400, /* Miscellaneous Technical: ⌐ ⌂ ⌠ ⌡ */
53    0x2500, 0x2580, /* Box Drawing: ═ ║ ╗ ╔ ╩ */
54    0x2580, 0x25a0, /* Block Elements: ▛ ▞ ░ ▒ ▓ */
55    0, 0
56};
57
58static void fix_glyph(FT_Bitmap *, uint32_t, unsigned int, unsigned int);
59static int printf_hex(char const *, uint8_t *, int);
60static int printf_u32(char const *, uint32_t);
61static int printf_u16(char const *, uint16_t);
62
63int main(int argc, char *argv[])
64{
65    PangoContext *cx;
66    PangoFontDescription *fd;
67    PangoFontMap *fm;
68    PangoLayout *l;
69    PangoRectangle r;
70
71    FT_Bitmap img;
72    int width, height, b, i, n, blocks, glyphs;
73    unsigned int glyph_size, control_size, data_size;
74    uint8_t *glyph_data;
75
76    unsigned int bpp, dpi;
77    char const *prefix, *font;
78
79    if(argc != 5)
80    {
81        fprintf(stderr, "%s: wrong argument count\n", argv[0]);
82        fprintf(stderr, "usage: %s <prefix> <font> <dpi> <bpp>\n", argv[0]);
83        fprintf(stderr, "eg: %s monospace9 \"Monospace 9\" 96 4\n", argv[0]);
84        return -1;
85    }
86
87    prefix = argv[1];
88    font = argv[2];
89    dpi = atoi(argv[3]);
90    bpp = atoi(argv[4]);
91
92    if(dpi == 0 || (bpp != 1 && bpp != 2 && bpp != 4 && bpp != 8))
93    {
94        fprintf(stderr, "%s: invalid argument\n", argv[0]);
95        return -1;
96    }
97
98    fprintf(stderr, "Font \"%s\", %i dpi, %i bpp\n", font, dpi, bpp);
99
100    /* Initialise Pango */
101    fm = pango_ft2_font_map_new();
102    pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fm), dpi, dpi);
103    cx = pango_ft2_font_map_create_context(PANGO_FT2_FONT_MAP(fm));
104
105    l = pango_layout_new(cx);
106    if(!l)
107    {
108        fprintf(stderr, "%s: unable to initialise pango\n", argv[0]);
109        g_object_unref(cx);
110        return -1;
111    }
112
113    fd = pango_font_description_from_string(font);
114    pango_layout_set_font_description(l, fd);
115    pango_font_description_free(fd);
116
117    /* Initialise our FreeType2 bitmap */
118    img.width = 256;
119    img.pitch = 256;
120    img.rows = 256;
121    img.buffer = malloc(256 * 256);
122    img.num_grays = 256;
123    img.pixel_mode = ft_pixel_mode_grays;
124
125    /* Test rendering so that we know the glyph width */
126    pango_layout_set_markup(l, "@", -1);
127    pango_layout_get_extents(l, NULL, &r);
128    width = PANGO_PIXELS(r.width);
129    height = PANGO_PIXELS(r.height);
130    glyph_size = ((width * height) + (8 / bpp) - 1) / (8 / bpp);
131    glyph_data = malloc(glyph_size);
132
133    /* Compute blocks and glyphs count */
134    blocks = 0;
135    glyphs = 0;
136    for(b = 0; blocklist[b + 1]; b += 2)
137    {
138        blocks++;
139        glyphs += blocklist[b + 1] - blocklist[b];
140    }
141
142    control_size = 24 + 12 * blocks + 8 * glyphs;
143    data_size = glyph_size * glyphs;
144
145    /* Let's go! */
146    printf("/* libcucul font file\n");
147    printf(" * \"%s\": %i dpi, %i bpp, %ix%i glyphs\n",
148           font, dpi, bpp, width, height);
149    printf(" * Automatically generated by tools/makefont.c:\n");
150    printf(" *   tools/makefont %s \"%s\" %i %i\n", prefix, font, dpi, bpp);
151    printf(" */\n");
152    printf("\n");
153
154    printf("static unsigned int const %s_size = %i;\n",
155           prefix, 8 + control_size + data_size);
156    printf("static unsigned char const %s_data[] =\n", prefix);
157
158    printf("/* file: */\n");
159    printf("\"CACA\" /* caca_header */\n");
160    printf("\"FONT\" /* caca_file_type */\n");
161    printf("\n");
162
163    printf("/* font_header: */\n");
164    printf_u32("\"%s\" /* control_size */\n", control_size);
165    printf_u32("\"%s\" /* data_size */\n", data_size);
166    printf_u16("\"%s\" /* version */\n", 1);
167    printf_u16("\"%s\" /* blocks */\n", blocks);
168    printf_u32("\"%s\" /* glyphs */\n", glyphs);
169    printf_u16("\"%s\" /* bpp */\n", bpp);
170    printf_u16("\"%s\" /* width */\n", width);
171    printf_u16("\"%s\" /* height */\n", height);
172    printf_u16("\"%s\" /* flags */\n", 1);
173    printf("\n");
174
175    printf("/* block_info: */\n");
176    n = 0;
177    for(b = 0; blocklist[b + 1]; b += 2)
178    {
179        printf_u32("\"%s", blocklist[b]);
180        printf_u32("%s", blocklist[b + 1]);
181        printf_u32("%s\"\n", n);
182        n += blocklist[b + 1] - blocklist[b];
183    }
184    printf("\n");
185
186    printf("/* glyph_info: */\n");
187    n = 0;
188    for(b = 0; blocklist[b + 1]; b += 2)
189    {
190        for(i = blocklist[b]; i < blocklist[b + 1]; i++)
191        {
192            printf_u16("\"%s", width);
193            printf_u16("%s", height);
194            printf_u32("%s\"\n", n * glyph_size);
195            n++;
196        }
197    }
198    printf("\n");
199
200    printf("/* font_data: */\n");
201    for(b = 0; blocklist[b + 1]; b += 2)
202    {
203        for(i = blocklist[b]; i < blocklist[b + 1]; i++)
204        {
205            unsigned int ch = i;
206            char buf[10];
207            int x, y, bytes;
208
209            bytes = _cucul_utf32_to_utf8(buf, ch);
210            buf[bytes] = '\0';
211
212            /* Print glyph value in comment */
213            printf("/* U+%.04X: \"", i);
214
215            if(i < 0x20 || (i >= 0x80 && i <= 0xa0))
216                printf("\\x%.02x\" */", i);
217            else
218                printf("%s\" */ ", buf);
219
220            /* Render glyph on a bitmap */
221            pango_layout_set_text(l, buf, -1);
222            memset(glyph_data, 0, glyph_size);
223            memset(img.buffer, 0, img.pitch * height);
224            pango_ft2_render_layout(&img, l, 0, 0);
225
226            /* Fix glyphs that we know how to handle better */
227            fix_glyph(&img, ch, width, height);
228
229            /* Write bitmap as an escaped C string */
230            n = 0;
231            for(y = 0; y < height; y++)
232            {
233                for(x = 0; x < width; x++)
234                {
235                    uint8_t pixel = img.buffer[y * img.pitch + x];
236
237                    pixel >>= (8 - bpp);
238                    glyph_data[n / 8] |= pixel << (8 - bpp - (n % 8));
239                    n += bpp;
240                }
241            }
242            printf_hex("\"%s\"\n", glyph_data, glyph_size);
243        }
244    }
245
246    printf(";\n");
247
248    free(img.buffer);
249    g_object_unref(l);
250    g_object_unref(cx);
251
252    return 0;
253}
254
255/*
256 * XXX: the following functions are local
257 */
258
259static void fix_glyph(FT_Bitmap *i, uint32_t ch,
260                      unsigned int width, unsigned int height)
261{
262    unsigned int x, y;
263
264    switch(ch)
265    {
266    case 0x00002580: /* ▀ */
267        for(y = 0; y < height; y++)
268            for(x = 0; x < width; x++)
269                i->buffer[x + y * i->pitch] = y < height / 2 ? 0xff : 0x00;
270        if(height & 1)
271            for(x = 0; x < width; x++)
272                i->buffer[x + (height / 2) * i->pitch] = 0x7f;
273        break;
274    case 0x00002584: /* ▄ */
275        for(y = 0; y < height; y++)
276            for(x = 0; x < width; x++)
277                i->buffer[x + y * i->pitch] = y < height / 2 ? 0x00 : 0xff;
278        if(height & 1)
279            for(x = 0; x < width; x++)
280                i->buffer[x + (height / 2) * i->pitch] = 0x7f;
281        break;
282    case 0x0000258c: /* ▌ */
283        for(y = 0; y < height; y++)
284            for(x = 0; x < width; x++)
285                i->buffer[x + y * i->pitch] = x < width / 2 ? 0xff : 0x00;
286        if(width & 1)
287            for(y = 0; y < height; y++)
288                i->buffer[(width / 2) + y * i->pitch] = 0x7f;
289        break;
290    case 0x00002590: /* ▐ */
291        for(y = 0; y < height; y++)
292            for(x = 0; x < width; x++)
293                i->buffer[x + y * i->pitch] = x < width / 2 ? 0x00 : 0xff;
294        if(width & 1)
295            for(y = 0; y < height; y++)
296                i->buffer[(width / 2) + y * i->pitch] = 0x7f;
297        break;
298    case 0x000025a0: /* ■ */
299        for(y = 0; y < height; y++)
300            for(x = 0; x < width; x++)
301                i->buffer[x + y * i->pitch] =
302                    (y >= height / 4) && (y < 3 * height / 4) ? 0xff : 0x00;
303        if(height & 3)
304            for(x = 0; x < width; x++) /* FIXME: could be more precise */
305                i->buffer[x + (height / 4) * i->pitch] =
306                    i->buffer[x + (3 * height / 4) * i->pitch] = 0x7f;
307        break;
308    case 0x00002588: /* █ */
309        memset(i->buffer, 0xff, height * i->pitch);
310        break;
311    case 0x00002593: /* ▓ */
312        for(y = 0; y < height; y++)
313            for(x = 0; x < width; x++)
314                i->buffer[x + y * i->pitch] =
315                    ((x + 2 * (y & 1)) & 3) ? 0xff : 0x00;
316        break;
317    case 0x00002592: /* ▒ */
318        for(y = 0; y < height; y++)
319            for(x = 0; x < width; x++)
320                i->buffer[x + y * i->pitch] = ((x + y) & 1) ? 0xff : 0x00;
321        break;
322    case 0x00002591: /* ░ */
323        for(y = 0; y < height; y++)
324            for(x = 0; x < width; x++)
325                i->buffer[x + y * i->pitch] =
326                    ((x + 2 * (y & 1)) & 3) ? 0x00 : 0xff;
327        break;
328    }
329}
330
331static int printf_u32(char const *fmt, uint32_t i)
332{
333    uint32_t ni = hton32(i);
334    return printf_hex(fmt, (uint8_t *)&ni, 4);
335}
336
337static int printf_u16(char const *fmt, uint16_t i)
338{
339    uint16_t ni = hton16(i);
340    return printf_hex(fmt, (uint8_t *)&ni, 2);
341}
342
343static int printf_hex(char const *fmt, uint8_t *data, int bytes)
344{
345    char buf[BUFSIZ];
346    char *parser = buf;
347    int rewind = 0; /* we use this variable to rewind 2 bytes after \000
348                     * was printed when the next char starts with "\", too. */
349
350    while(bytes--)
351    {
352        uint8_t ch = *data++;
353        if(ch == '\\' || ch == '"')
354        {
355            parser -= rewind;
356            parser += sprintf(parser, "\\%c", ch);
357            rewind = 0;
358        }
359        else if(ch >= 0x20 && ch < 0x7f)
360        {
361            parser += sprintf(parser, "%c", ch);
362            rewind = 0;
363        }
364        else
365        {
366            parser -= rewind;
367            parser += sprintf(parser, "\\%.03o", ch);
368            rewind = ch ? 0 : 2;
369        }
370    }
371
372    parser -= rewind;
373    parser[0] = '\0';
374
375    return printf(fmt, buf);
376}
377
Note: See TracBrowser for help on using the repository browser.