"Fossies" - the Fresh Open Source Software Archive 
Member "libcaca-0.99.beta20/tools/makefont.c" (19 Oct 2021, 14893 Bytes) of package /linux/privat/libcaca-0.99.beta20.tar.bz2:
1 /*
2 * makefont create libcaca font data
3 * Copyright © 2006—2021 Sam Hocevar <sam@hocevar.net>
4 * All Rights Reserved
5 *
6 * This program is free software. It comes without any warranty, to
7 * the extent permitted by applicable law. You can redistribute it
8 * and/or modify it under the terms of the Do What the Fuck You Want
9 * to Public License, Version 2, as published by Sam Hocevar. See
10 * http://www.wtfpl.net/ for more details.
11 *
12 * Usage:
13 * makefont <prefix> <font> <dpi> <bpp>
14 */
15
16 #include "config.h"
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stdint.h>
21
22 #if defined HAVE_ARPA_INET_H
23 # include <arpa/inet.h>
24 #elif defined HAVE_NETINET_IN_H
25 # include <netinet/in.h>
26 #endif
27
28 #include <pango/pango.h>
29 #include <pango/pangoft2.h>
30
31 #include "caca_stubs.h"
32 #include "caca.h"
33
34 /* Split our big strings into chunks of 480 characters, because it is
35 * the multiple of 32 directly below 509, which is the maximum allowed
36 * string size in C89. */
37 #define STRING_CHUNKS 480
38
39 /* This list is built so that it includes all of ASCII, Latin-1, CP-437,
40 * and the UTF-8 glyphs necessary for canvas rotation and mirroring. */
41 static unsigned int const blocklist[] =
42 {
43 0x0020, 0x0080, /* Basic latin: A, B, C, a, b, c */
44 #if 0
45 0x0080, 0x0100, /* Latin-1 Supplement: Ä, Ç, å, ß */
46 0x0100, 0x0180, /* Latin Extended-A: Ā č Ō œ */
47 0x0180, 0x0250, /* Latin Extended-B: Ǝ Ƹ */
48 0x0250, 0x02b0, /* IPA Extensions: ɐ ɔ ɘ ʌ ʍ */
49 0x0370, 0x0400, /* Greek and Coptic: Λ α β */
50 0x0400, 0x0500, /* Cyrillic: И Я */
51 0x0530, 0x0590, /* Armenian: Ո */
52 0x1401, 0x1677, /* Unified Canadian Aboriginal Syllabics: ᒐ ᗡ */
53 0x1d00, 0x1d80, /* Phonetic Extensions: ᴉ ᵷ */
54 0x2000, 0x2070, /* General Punctuation: ‘’ “” */
55 0x2100, 0x2150, /* Letterlike Symbols: Ⅎ */
56 0x2200, 0x2300, /* Mathematical Operators: ∀ √ ∞ ∙ */
57 0x2300, 0x2400, /* Miscellaneous Technical: ⌐ ⌂ ⌠ ⌡ */
58 0x2500, 0x2580, /* Box Drawing: ═ ║ ╗ ╔ ╩ */
59 0x2580, 0x25a0, /* Block Elements: ▛ ▞ ░ ▒ ▓ */
60 0x25a0, 0x2600, /* Geometric Shapes: ◆ ○ ● */
61 0x2600, 0x2700, /* Miscellaneous Symbols: ♥ ★ ☭ */
62 0x3000, 0x3040, /* CJK Symbols and Punctuation: 。「」 */
63 0x3040, 0x30a0, /* Hiragana: で す */
64 0x30a0, 0x3100, /* Katakana: ロ ル */
65 0xff00, 0xfff0, /* Halfwidth and Fullwidth Forms: A, B, C, a, b, c */
66 0x10400, 0x10450, /* Deseret: 𐐒 𐐋 */
67 #endif
68 0, 0
69 };
70
71 struct glyph
72 {
73 uint32_t unicode;
74 char buf[10];
75 unsigned int same_as;
76 unsigned int data_offset;
77 unsigned int data_width;
78 unsigned int data_size;
79 };
80
81 static void fix_glyph(FT_Bitmap *, uint32_t, unsigned int, unsigned int);
82 static int printf_unicode(struct glyph *);
83 static int printf_hex(char const *, uint8_t *, int);
84 static int printf_u32(char const *, uint32_t);
85 static int printf_u16(char const *, uint16_t);
86
87 /* Counter for written bytes */
88 static int written = 0;
89
90 int main(int argc, char *argv[])
91 {
92 PangoContext *cx;
93 PangoFontDescription *fd;
94 PangoFontMap *fm;
95 PangoLayout *l;
96 PangoRectangle r;
97
98 FT_Bitmap img;
99 int stdwidth, fullwidth, height, blocks, glyphs, fullglyphs;
100 unsigned int n, b, i;
101 unsigned int stdsize, fullsize, control_size, data_size, current_offset;
102 uint8_t *glyph_data;
103 struct glyph *gtab;
104
105 unsigned int bpp, dpi;
106 char const *prefix, *font;
107
108 if(argc != 5)
109 {
110 fprintf(stderr, "%s: wrong argument count\n", argv[0]);
111 fprintf(stderr, "usage: %s <prefix> <font> <dpi> <bpp>\n", argv[0]);
112 fprintf(stderr, "eg: %s monospace9 \"Monospace 9\" 96 4\n", argv[0]);
113 return -1;
114 }
115
116 prefix = argv[1];
117 font = argv[2];
118 dpi = atoi(argv[3]);
119 bpp = atoi(argv[4]);
120
121 if(dpi == 0 || (bpp != 1 && bpp != 2 && bpp != 4 && bpp != 8))
122 {
123 fprintf(stderr, "%s: invalid argument\n", argv[0]);
124 return -1;
125 }
126
127 fprintf(stderr, "Font \"%s\", %i dpi, %i bpp\n", font, dpi, bpp);
128
129 /* Initialise Pango */
130 fm = pango_ft2_font_map_new();
131 pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fm), dpi, dpi);
132 cx = pango_ft2_font_map_create_context(PANGO_FT2_FONT_MAP(fm));
133
134 l = pango_layout_new(cx);
135 if(!l)
136 {
137 fprintf(stderr, "%s: unable to initialise pango\n", argv[0]);
138 g_object_unref(cx);
139 return -1;
140 }
141
142 fd = pango_font_description_from_string(font);
143 pango_layout_set_font_description(l, fd);
144 pango_font_description_free(fd);
145
146 /* Initialise our FreeType2 bitmap */
147 img.width = 256;
148 img.pitch = 256;
149 img.rows = 256;
150 img.buffer = malloc(256 * 256);
151 img.num_grays = 256;
152 img.pixel_mode = ft_pixel_mode_grays;
153
154 /* Test rendering so that we know the glyph width */
155 pango_layout_set_markup(l, "@", -1);
156 pango_layout_get_extents(l, NULL, &r);
157 stdwidth = PANGO_PIXELS(r.width);
158 fullwidth = stdwidth * 2;
159 height = PANGO_PIXELS(r.height);
160 stdsize = ((stdwidth * height) + (8 / bpp) - 1) / (8 / bpp);
161 fullsize = ((fullwidth * height) + (8 / bpp) - 1) / (8 / bpp);
162
163 /* Compute blocks and glyphs count */
164 blocks = 0;
165 glyphs = 0;
166 fullglyphs = 0;
167 for(b = 0; blocklist[b + 1]; b += 2)
168 {
169 blocks++;
170 glyphs += blocklist[b + 1] - blocklist[b];
171 for(i = blocklist[b]; i < blocklist[b + 1]; i++)
172 if(caca_utf32_is_fullwidth(i))
173 fullglyphs++;
174 }
175
176 control_size = 28 + 12 * blocks + 8 * glyphs;
177 data_size = stdsize * (glyphs - fullglyphs) + fullsize * fullglyphs;
178
179 gtab = malloc(glyphs * sizeof(struct glyph));
180 glyph_data = malloc(data_size);
181
182 /* Let's go! */
183 printf("/* libcaca font file\n");
184 printf(" * \"%s\": %i dpi, %i bpp, %ix%i/%ix%i glyphs\n",
185 font, dpi, bpp, stdwidth, height, fullwidth, height);
186 printf(" * Automatically generated by tools/makefont.c:\n");
187 printf(" * tools/makefont %s \"%s\" %i %i\n", prefix, font, dpi, bpp);
188 printf(" */\n");
189 printf("\n");
190
191 printf("static size_t const %s_size = %i;\n",
192 prefix, 4 + control_size + data_size);
193 printf("static uint8_t const %s_data[%i] =\n",
194 prefix, 4 + control_size + data_size);
195 printf("{\n");
196
197 printf("/* file: */\n");
198 printf("0xCA,0xCA, /* caca_header */\n");
199 written += 2;
200 printf("'F','T', /* caca_file_type */\n");
201 written += 2;
202 printf("\n");
203
204 printf("/* font_header: */\n");
205 printf_u32("%s /* control_size */\n", control_size);
206 printf_u32("%s /* data_size */\n", data_size);
207 printf_u16("%s /* version */\n", 1);
208 printf_u16("%s /* blocks */\n", blocks);
209 printf_u32("%s /* glyphs */\n", glyphs);
210 printf_u16("%s /* bpp */\n", bpp);
211 printf_u16("%s /* std width */\n", stdwidth);
212 printf_u16("%s /* std height */\n", height);
213 printf_u16("%s /* max width */\n", fullwidth);
214 printf_u16("%s /* max height */\n", height);
215 printf_u16("%s /* flags */\n", 1);
216 printf("\n");
217
218 printf("/* block_info: */\n");
219 n = 0;
220 for(b = 0; blocklist[b + 1]; b += 2)
221 {
222 printf_u32("%s", blocklist[b]);
223 printf_u32("%s", blocklist[b + 1]);
224 printf_u32("%s\n", n);
225 n += blocklist[b + 1] - blocklist[b];
226 }
227 printf("\n");
228
229 /* Render all glyphs, so that we can know their offset */
230 current_offset = n = 0;
231 for(b = 0; blocklist[b + 1]; b += 2)
232 {
233 for(i = blocklist[b]; i < blocklist[b + 1]; i++)
234 {
235 int x, y, bytes, current_width = stdwidth;
236 unsigned int k, current_size = stdsize;
237
238 if(caca_utf32_is_fullwidth(i))
239 {
240 current_width = fullwidth;
241 current_size = fullsize;
242 }
243 gtab[n].unicode = i;
244 bytes = caca_utf32_to_utf8(gtab[n].buf, gtab[n].unicode);
245 gtab[n].buf[bytes] = '\0';
246
247 /* Render glyph on a bitmap */
248 pango_layout_set_text(l, gtab[n].buf, -1);
249 memset(img.buffer, 0, img.pitch * height);
250 pango_ft2_render_layout(&img, l, 0, 0);
251
252 /* Fix glyphs that we know how to handle better */
253 fix_glyph(&img, gtab[n].unicode, current_width, height);
254
255 /* Write bitmap as an escaped C string */
256 memset(glyph_data + current_offset, 0, current_size);
257 k = 0;
258 for(y = 0; y < height; y++)
259 {
260 for(x = 0; x < current_width; x++)
261 {
262 uint8_t pixel = img.buffer[y * img.pitch + x];
263
264 pixel >>= (8 - bpp);
265 glyph_data[current_offset + k / 8]
266 |= pixel << (8 - bpp - (k % 8));
267 k += bpp;
268 }
269 }
270
271 /* Check whether this is the same glyph as another one. Please
272 * don't bullshit me about sorting, hashing and stuff like that,
273 * our data is small enough for this to work. */
274 for(k = 0; k < n; k++)
275 {
276 if(gtab[k].data_size != current_size)
277 continue;
278 #if 0
279 if(!memcmp(glyph_data + gtab[k].data_offset,
280 glyph_data + current_offset, current_size))
281 break;
282 #endif
283 }
284
285 gtab[n].data_offset = current_offset;
286 gtab[n].data_width = current_width;
287 gtab[n].data_size = current_size;
288 gtab[n].same_as = k;
289
290 if(k == n)
291 current_offset += current_size;
292
293 n++;
294 }
295 }
296
297 printf("/* glyph_info: */\n");
298 n = 0;
299 for(b = 0; blocklist[b + 1]; b += 2)
300 {
301 for(i = blocklist[b]; i < blocklist[b + 1]; i++)
302 {
303 printf_u16("%s", gtab[n].data_width);
304 printf_u16("%s", height);
305 printf_u32("%s\n", gtab[gtab[n].same_as].data_offset);
306 n++;
307 }
308 }
309 printf("\n");
310
311 printf("/* font_data: */\n");
312 n = 0;
313 for(b = 0; blocklist[b + 1]; b += 2)
314 {
315 for(i = blocklist[b]; i < blocklist[b + 1]; i++)
316 {
317 /* Print glyph value in comment */
318 printf("/* ");
319 printf_unicode(>ab[n]);
320
321 if(gtab[n].same_as == n)
322 {
323 char const *lut = " .:nmW@";
324 printf("\n");
325 for (int y = 0; y < height; ++y)
326 {
327 for (int x = 0; x < gtab[n].data_width; ++x)
328 {
329 int val = glyph_data[gtab[n].data_offset + y * gtab[n].data_width + x];
330 char ch = lut[val * val * 7 / 256 / 256];
331 printf("%c%c", ch, ch);
332 }
333 printf("\n");
334 }
335 //printf_hex(" */ %s\n",
336 // glyph_data + gtab[n].data_offset, gtab[n].data_size);
337 }
338 else
339 {
340 printf(" is ");
341 printf_unicode(>ab[gtab[n].same_as]);
342 printf(" */\n");
343 }
344
345 n++;
346 }
347 }
348
349 printf("};\n");
350
351 free(img.buffer);
352 free(gtab);
353 free(glyph_data);
354 g_object_unref(l);
355 g_object_unref(cx);
356 g_object_unref(fm);
357
358 return 0;
359 }
360
361 /*
362 * XXX: the following functions are local
363 */
364
365 static void fix_glyph(FT_Bitmap *i, uint32_t ch,
366 unsigned int width, unsigned int height)
367 {
368 unsigned int x, y;
369
370 switch(ch)
371 {
372 case 0x00002580: /* ▀ */
373 for(y = 0; y < height; y++)
374 for(x = 0; x < width; x++)
375 i->buffer[x + y * i->pitch] = y < height / 2 ? 0xff : 0x00;
376 if(height & 1)
377 for(x = 0; x < width; x++)
378 i->buffer[x + (height / 2) * i->pitch] = 0x7f;
379 break;
380 case 0x00002584: /* ▄ */
381 for(y = 0; y < height; y++)
382 for(x = 0; x < width; x++)
383 i->buffer[x + y * i->pitch] = y < height / 2 ? 0x00 : 0xff;
384 if(height & 1)
385 for(x = 0; x < width; x++)
386 i->buffer[x + (height / 2) * i->pitch] = 0x7f;
387 break;
388 case 0x0000258c: /* ▌ */
389 for(y = 0; y < height; y++)
390 for(x = 0; x < width; x++)
391 i->buffer[x + y * i->pitch] = x < width / 2 ? 0xff : 0x00;
392 if(width & 1)
393 for(y = 0; y < height; y++)
394 i->buffer[(width / 2) + y * i->pitch] = 0x7f;
395 break;
396 case 0x00002590: /* ▐ */
397 for(y = 0; y < height; y++)
398 for(x = 0; x < width; x++)
399 i->buffer[x + y * i->pitch] = x < width / 2 ? 0x00 : 0xff;
400 if(width & 1)
401 for(y = 0; y < height; y++)
402 i->buffer[(width / 2) + y * i->pitch] = 0x7f;
403 break;
404 case 0x000025a0: /* ■ */
405 for(y = 0; y < height; y++)
406 for(x = 0; x < width; x++)
407 i->buffer[x + y * i->pitch] =
408 (y >= height / 4) && (y < 3 * height / 4) ? 0xff : 0x00;
409 if(height & 3)
410 for(x = 0; x < width; x++) /* FIXME: could be more precise */
411 i->buffer[x + (height / 4) * i->pitch] =
412 i->buffer[x + (3 * height / 4) * i->pitch] = 0x7f;
413 break;
414 case 0x00002588: /* █ */
415 memset(i->buffer, 0xff, height * i->pitch);
416 break;
417 case 0x00002593: /* ▓ */
418 for(y = 0; y < height; y++)
419 for(x = 0; x < width; x++)
420 i->buffer[x + y * i->pitch] =
421 ((x + 2 * (y & 1)) & 3) ? 0xff : 0x00;
422 break;
423 case 0x00002592: /* ▒ */
424 for(y = 0; y < height; y++)
425 for(x = 0; x < width; x++)
426 i->buffer[x + y * i->pitch] = ((x + y) & 1) ? 0xff : 0x00;
427 break;
428 case 0x00002591: /* ░ */
429 for(y = 0; y < height; y++)
430 for(x = 0; x < width; x++)
431 i->buffer[x + y * i->pitch] =
432 ((x + 2 * (y & 1)) & 3) ? 0x00 : 0xff;
433 break;
434 }
435 }
436
437 static int printf_unicode(struct glyph *g)
438 {
439 int wr = 0;
440
441 wr += printf("U+%.04X: \"", g->unicode);
442
443 if(g->unicode < 0x20 || (g->unicode >= 0x7f && g->unicode <= 0xa0))
444 wr += printf("\\x%.02x\"", g->unicode);
445 else
446 wr += printf("%s\"", g->buf);
447
448 return wr;
449 }
450
451 static int printf_u32(char const *fmt, uint32_t i)
452 {
453 uint32_t ni = hton32(i);
454 return printf_hex(fmt, (uint8_t *)&ni, 4);
455 }
456
457 static int printf_u16(char const *fmt, uint16_t i)
458 {
459 uint16_t ni = hton16(i);
460 return printf_hex(fmt, (uint8_t *)&ni, 2);
461 }
462
463 static int printf_hex(char const *fmt, uint8_t *data, int bytes)
464 {
465 char buf[BUFSIZ];
466 char *parser = buf;
467
468 while(bytes--)
469 parser += sprintf(parser, "%i,", (unsigned int)*data++);
470 parser[0] = '\0';
471
472 return printf(fmt, buf);
473 }
474