25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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