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.

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