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

makefont.c 15 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  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. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. *
  14. * Usage:
  15. * makefont <prefix> <font> <dpi> <bpp>
  16. */
  17. #include "config.h"
  18. #include "common.h"
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <stdint.h>
  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. #include "cucul.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. 0x3000, 0x3040, /* CJK Symbols and Punctuation: 。「」 */
  54. 0x3040, 0x30a0, /* Hiragana: で す */
  55. 0x30a0, 0x3100, /* Katakana: ロ ル */
  56. 0, 0
  57. };
  58. struct glyph
  59. {
  60. uint32_t unicode;
  61. char buf[10];
  62. unsigned int same_as;
  63. unsigned int data_offset;
  64. unsigned int data_width;
  65. unsigned int data_size;
  66. };
  67. static void fix_glyph(FT_Bitmap *, uint32_t, unsigned int, unsigned int);
  68. static int printf_unicode(struct glyph *);
  69. static int printf_hex(char const *, uint8_t *, int);
  70. static int printf_u32(char const *, uint32_t);
  71. static int printf_u16(char const *, uint16_t);
  72. /* Counter for written bytes */
  73. static int written = 0;
  74. int main(int argc, char *argv[])
  75. {
  76. PangoContext *cx;
  77. PangoFontDescription *fd;
  78. PangoFontMap *fm;
  79. PangoLayout *l;
  80. PangoRectangle r;
  81. FT_Bitmap img;
  82. int stdwidth, fullwidth, height, blocks, glyphs, fullglyphs;
  83. unsigned int n, b, i;
  84. unsigned int stdsize, fullsize, control_size, data_size, current_offset;
  85. uint8_t *glyph_data;
  86. struct glyph *gtab;
  87. unsigned int bpp, dpi;
  88. char const *prefix, *font;
  89. if(argc != 5)
  90. {
  91. fprintf(stderr, "%s: wrong argument count\n", argv[0]);
  92. fprintf(stderr, "usage: %s <prefix> <font> <dpi> <bpp>\n", argv[0]);
  93. fprintf(stderr, "eg: %s monospace9 \"Monospace 9\" 96 4\n", argv[0]);
  94. return -1;
  95. }
  96. prefix = argv[1];
  97. font = argv[2];
  98. dpi = atoi(argv[3]);
  99. bpp = atoi(argv[4]);
  100. if(dpi == 0 || (bpp != 1 && bpp != 2 && bpp != 4 && bpp != 8))
  101. {
  102. fprintf(stderr, "%s: invalid argument\n", argv[0]);
  103. return -1;
  104. }
  105. fprintf(stderr, "Font \"%s\", %i dpi, %i bpp\n", font, dpi, bpp);
  106. /* Initialise Pango */
  107. fm = pango_ft2_font_map_new();
  108. pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fm), dpi, dpi);
  109. cx = pango_ft2_font_map_create_context(PANGO_FT2_FONT_MAP(fm));
  110. l = pango_layout_new(cx);
  111. if(!l)
  112. {
  113. fprintf(stderr, "%s: unable to initialise pango\n", argv[0]);
  114. g_object_unref(cx);
  115. return -1;
  116. }
  117. fd = pango_font_description_from_string(font);
  118. pango_layout_set_font_description(l, fd);
  119. pango_font_description_free(fd);
  120. /* Initialise our FreeType2 bitmap */
  121. img.width = 256;
  122. img.pitch = 256;
  123. img.rows = 256;
  124. img.buffer = malloc(256 * 256);
  125. img.num_grays = 256;
  126. img.pixel_mode = ft_pixel_mode_grays;
  127. /* Test rendering so that we know the glyph width */
  128. pango_layout_set_markup(l, "@", -1);
  129. pango_layout_get_extents(l, NULL, &r);
  130. stdwidth = PANGO_PIXELS(r.width);
  131. fullwidth = stdwidth * 2;
  132. height = PANGO_PIXELS(r.height);
  133. stdsize = ((stdwidth * height) + (8 / bpp) - 1) / (8 / bpp);
  134. fullsize = ((fullwidth * height) + (8 / bpp) - 1) / (8 / bpp);
  135. /* Compute blocks and glyphs count */
  136. blocks = 0;
  137. glyphs = 0;
  138. fullglyphs = 0;
  139. for(b = 0; blocklist[b + 1]; b += 2)
  140. {
  141. blocks++;
  142. glyphs += blocklist[b + 1] - blocklist[b];
  143. for(i = blocklist[b]; i < blocklist[b + 1]; i++)
  144. if(cucul_utf32_is_fullwidth(i))
  145. fullglyphs++;
  146. }
  147. control_size = 28 + 12 * blocks + 8 * glyphs;
  148. data_size = stdsize * (glyphs - fullglyphs) + fullsize * fullglyphs;
  149. gtab = malloc(glyphs * sizeof(struct glyph));
  150. glyph_data = malloc(data_size);
  151. /* Let's go! */
  152. printf("/* libcucul font file\n");
  153. printf(" * \"%s\": %i dpi, %i bpp, %ix%i/%ix%i glyphs\n",
  154. font, dpi, bpp, stdwidth, height, fullwidth, height);
  155. printf(" * Automatically generated by tools/makefont.c:\n");
  156. printf(" * tools/makefont %s \"%s\" %i %i\n", prefix, font, dpi, bpp);
  157. printf(" */\n");
  158. printf("\n");
  159. printf("static unsigned int const %s_size = %i;\n",
  160. prefix, 4 + control_size + data_size);
  161. printf("static struct {\n");
  162. printf("char ");
  163. for(i = 0; (i + 1) * STRING_CHUNKS < 8 + control_size + data_size; i++)
  164. printf("d%x[%i],%c", i, STRING_CHUNKS, (i % 6) == 5 ? '\n' : ' ');
  165. printf("d%x[%i];\n", i, 4 + control_size + data_size - i * STRING_CHUNKS);
  166. printf("} %s_data = {\n", prefix);
  167. printf("\n");
  168. printf("/* file: */\n");
  169. printf("\"\\xCA\\xCA\" /* caca_header */\n");
  170. written += 2;
  171. printf("\"FT\" /* caca_file_type */\n");
  172. written += 2;
  173. printf("\n");
  174. printf("/* font_header: */\n");
  175. printf_u32("\"%s\" /* control_size */\n", control_size);
  176. printf_u32("\"%s\" /* data_size */\n", data_size);
  177. printf_u16("\"%s\" /* version */\n", 1);
  178. printf_u16("\"%s\" /* blocks */\n", blocks);
  179. printf_u32("\"%s\" /* glyphs */\n", glyphs);
  180. printf_u16("\"%s\" /* bpp */\n", bpp);
  181. printf_u16("\"%s\" /* std width */\n", stdwidth);
  182. printf_u16("\"%s\" /* std height */\n", height);
  183. printf_u16("\"%s\" /* max width */\n", fullwidth);
  184. printf_u16("\"%s\" /* max height */\n", height);
  185. printf_u16("\"%s\" /* flags */\n", 1);
  186. printf("\n");
  187. printf("/* block_info: */\n");
  188. n = 0;
  189. for(b = 0; blocklist[b + 1]; b += 2)
  190. {
  191. printf_u32("\"%s", blocklist[b]);
  192. printf_u32("%s", blocklist[b + 1]);
  193. printf_u32("%s\"\n", n);
  194. n += blocklist[b + 1] - blocklist[b];
  195. }
  196. printf("\n");
  197. /* Render all glyphs, so that we can know their offset */
  198. current_offset = n = 0;
  199. for(b = 0; blocklist[b + 1]; b += 2)
  200. {
  201. for(i = blocklist[b]; i < blocklist[b + 1]; i++)
  202. {
  203. int x, y, bytes, current_width = stdwidth;
  204. unsigned int k, current_size = stdsize;
  205. if(cucul_utf32_is_fullwidth(i))
  206. {
  207. current_width = fullwidth;
  208. current_size = fullsize;
  209. }
  210. gtab[n].unicode = i;
  211. bytes = cucul_utf32_to_utf8(gtab[n].buf, gtab[n].unicode);
  212. gtab[n].buf[bytes] = '\0';
  213. /* Render glyph on a bitmap */
  214. pango_layout_set_text(l, gtab[n].buf, -1);
  215. memset(img.buffer, 0, img.pitch * height);
  216. pango_ft2_render_layout(&img, l, 0, 0);
  217. /* Fix glyphs that we know how to handle better */
  218. fix_glyph(&img, gtab[n].unicode, current_width, height);
  219. /* Write bitmap as an escaped C string */
  220. memset(glyph_data + current_offset, 0, current_size);
  221. k = 0;
  222. for(y = 0; y < height; y++)
  223. {
  224. for(x = 0; x < current_width; x++)
  225. {
  226. uint8_t pixel = img.buffer[y * img.pitch + x];
  227. pixel >>= (8 - bpp);
  228. glyph_data[current_offset + k / 8]
  229. |= pixel << (8 - bpp - (k % 8));
  230. k += bpp;
  231. }
  232. }
  233. /* Check whether this is the same glyph as another one. Please
  234. * don't bullshit me about sorting, hashing and stuff like that,
  235. * our data is small enough for this to work. */
  236. for(k = 0; k < n; k++)
  237. {
  238. if(gtab[k].data_size != current_size)
  239. continue;
  240. #if 0
  241. if(!memcmp(glyph_data + gtab[k].data_offset,
  242. glyph_data + current_offset, current_size))
  243. break;
  244. #endif
  245. }
  246. gtab[n].data_offset = current_offset;
  247. gtab[n].data_width = current_width;
  248. gtab[n].data_size = current_size;
  249. gtab[n].same_as = k;
  250. if(k == n)
  251. current_offset += current_size;
  252. n++;
  253. }
  254. }
  255. printf("/* glyph_info: */\n");
  256. n = 0;
  257. for(b = 0; blocklist[b + 1]; b += 2)
  258. {
  259. for(i = blocklist[b]; i < blocklist[b + 1]; i++)
  260. {
  261. printf_u16("\"%s", gtab[n].data_width);
  262. printf_u16("%s", height);
  263. printf_u32("%s\"\n", gtab[gtab[n].same_as].data_offset);
  264. n++;
  265. }
  266. }
  267. printf("\n");
  268. printf("/* font_data: */\n");
  269. n = 0;
  270. for(b = 0; blocklist[b + 1]; b += 2)
  271. {
  272. for(i = blocklist[b]; i < blocklist[b + 1]; i++)
  273. {
  274. /* Print glyph value in comment */
  275. printf("/* ");
  276. printf_unicode(&gtab[n]);
  277. if(gtab[n].same_as == n)
  278. printf_hex(" */ \"%s\"\n",
  279. glyph_data + gtab[n].data_offset, gtab[n].data_size);
  280. else
  281. {
  282. printf(" is ");
  283. printf_unicode(&gtab[gtab[n].same_as]);
  284. printf(" */\n");
  285. }
  286. n++;
  287. }
  288. }
  289. printf("};\n");
  290. free(img.buffer);
  291. free(gtab);
  292. free(glyph_data);
  293. g_object_unref(l);
  294. g_object_unref(cx);
  295. return 0;
  296. }
  297. /*
  298. * XXX: the following functions are local
  299. */
  300. static void fix_glyph(FT_Bitmap *i, uint32_t ch,
  301. unsigned int width, unsigned int height)
  302. {
  303. unsigned int x, y;
  304. switch(ch)
  305. {
  306. case 0x00002580: /* ▀ */
  307. for(y = 0; y < height; y++)
  308. for(x = 0; x < width; x++)
  309. i->buffer[x + y * i->pitch] = y < height / 2 ? 0xff : 0x00;
  310. if(height & 1)
  311. for(x = 0; x < width; x++)
  312. i->buffer[x + (height / 2) * i->pitch] = 0x7f;
  313. break;
  314. case 0x00002584: /* ▄ */
  315. for(y = 0; y < height; y++)
  316. for(x = 0; x < width; x++)
  317. i->buffer[x + y * i->pitch] = y < height / 2 ? 0x00 : 0xff;
  318. if(height & 1)
  319. for(x = 0; x < width; x++)
  320. i->buffer[x + (height / 2) * i->pitch] = 0x7f;
  321. break;
  322. case 0x0000258c: /* ▌ */
  323. for(y = 0; y < height; y++)
  324. for(x = 0; x < width; x++)
  325. i->buffer[x + y * i->pitch] = x < width / 2 ? 0xff : 0x00;
  326. if(width & 1)
  327. for(y = 0; y < height; y++)
  328. i->buffer[(width / 2) + y * i->pitch] = 0x7f;
  329. break;
  330. case 0x00002590: /* ▐ */
  331. for(y = 0; y < height; y++)
  332. for(x = 0; x < width; x++)
  333. i->buffer[x + y * i->pitch] = x < width / 2 ? 0x00 : 0xff;
  334. if(width & 1)
  335. for(y = 0; y < height; y++)
  336. i->buffer[(width / 2) + y * i->pitch] = 0x7f;
  337. break;
  338. case 0x000025a0: /* ■ */
  339. for(y = 0; y < height; y++)
  340. for(x = 0; x < width; x++)
  341. i->buffer[x + y * i->pitch] =
  342. (y >= height / 4) && (y < 3 * height / 4) ? 0xff : 0x00;
  343. if(height & 3)
  344. for(x = 0; x < width; x++) /* FIXME: could be more precise */
  345. i->buffer[x + (height / 4) * i->pitch] =
  346. i->buffer[x + (3 * height / 4) * i->pitch] = 0x7f;
  347. break;
  348. case 0x00002588: /* █ */
  349. memset(i->buffer, 0xff, height * i->pitch);
  350. break;
  351. case 0x00002593: /* ▓ */
  352. for(y = 0; y < height; y++)
  353. for(x = 0; x < width; x++)
  354. i->buffer[x + y * i->pitch] =
  355. ((x + 2 * (y & 1)) & 3) ? 0xff : 0x00;
  356. break;
  357. case 0x00002592: /* ▒ */
  358. for(y = 0; y < height; y++)
  359. for(x = 0; x < width; x++)
  360. i->buffer[x + y * i->pitch] = ((x + y) & 1) ? 0xff : 0x00;
  361. break;
  362. case 0x00002591: /* ░ */
  363. for(y = 0; y < height; y++)
  364. for(x = 0; x < width; x++)
  365. i->buffer[x + y * i->pitch] =
  366. ((x + 2 * (y & 1)) & 3) ? 0x00 : 0xff;
  367. break;
  368. }
  369. }
  370. static int printf_unicode(struct glyph *g)
  371. {
  372. int wr = 0;
  373. wr += printf("U+%.04X: \"", g->unicode);
  374. if(g->unicode < 0x20 || (g->unicode >= 0x7f && g->unicode <= 0xa0))
  375. wr += printf("\\x%.02x\"", g->unicode);
  376. else
  377. wr += printf("%s\"", g->buf);
  378. return wr;
  379. }
  380. static int printf_u32(char const *fmt, uint32_t i)
  381. {
  382. uint32_t ni = hton32(i);
  383. return printf_hex(fmt, (uint8_t *)&ni, 4);
  384. }
  385. static int printf_u16(char const *fmt, uint16_t i)
  386. {
  387. uint16_t ni = hton16(i);
  388. return printf_hex(fmt, (uint8_t *)&ni, 2);
  389. }
  390. static int printf_hex(char const *fmt, uint8_t *data, int bytes)
  391. {
  392. char buf[BUFSIZ];
  393. char *parser = buf;
  394. int rev = 0; /* we use this variable to rewind 2 bytes after \000
  395. * was printed when the next char starts with "\", too. */
  396. while(bytes--)
  397. {
  398. uint8_t ch = *data++;
  399. if(written == STRING_CHUNKS)
  400. {
  401. parser += sprintf(parser, "\", \"");
  402. written = 0;
  403. rev = 0;
  404. }
  405. if(ch == '\\' || ch == '"')
  406. {
  407. parser -= rev;
  408. parser += sprintf(parser, "\\%c", ch);
  409. rev = 0;
  410. }
  411. else if(ch >= 0x20 && ch < 0x7f)
  412. {
  413. parser += sprintf(parser, "%c", ch);
  414. rev = 0;
  415. }
  416. else
  417. {
  418. parser -= rev;
  419. parser += sprintf(parser, "\\%.03o", ch);
  420. rev = ch ? 0 : 2;
  421. }
  422. written++;
  423. }
  424. parser -= rev;
  425. parser[0] = '\0';
  426. return printf(fmt, buf);
  427. }