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