You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

378 lines
11 KiB

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