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.

преди 15 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
преди 18 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*
  2. * makefont create libcaca font data
  3. * Copyright (c) 2006 Sam Hocevar <sam@hocevar.net>
  4. * All Rights Reserved
  5. *
  6. * This program is free software. It comes without any warranty, to
  7. * the extent permitted by applicable law. You can redistribute it
  8. * and/or modify it under the terms of the Do What The Fuck You Want
  9. * To Public License, Version 2, as published by Sam Hocevar. See
  10. * http://sam.zoy.org/wtfpl/COPYING for more details.
  11. *
  12. * Usage:
  13. * makefont <prefix> <font> <dpi> <bpp>
  14. */
  15. #include "config.h"
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <stdint.h>
  19. #if defined HAVE_ARPA_INET_H
  20. # include <arpa/inet.h>
  21. #elif defined HAVE_NETINET_IN_H
  22. # include <netinet/in.h>
  23. #endif
  24. #include <pango/pango.h>
  25. #include <pango/pangoft2.h>
  26. #include "caca_stubs.h"
  27. #include "caca.h"
  28. /* Split our big strings into chunks of 480 characters, because it is
  29. * the multiple of 32 directly below 509, which is the maximum allowed
  30. * string size in C89. */
  31. #define STRING_CHUNKS 480
  32. /* This list is built so that it includes all of ASCII, Latin-1, CP-437,
  33. * and the UTF-8 glyphs necessary for canvas rotation and mirroring. */
  34. static unsigned int const blocklist[] =
  35. {
  36. 0x0000, 0x0080, /* Basic latin: A, B, C, a, b, c */
  37. 0x0080, 0x0100, /* Latin-1 Supplement: Ä, Ç, å, ß */
  38. 0x0100, 0x0180, /* Latin Extended-A: Ā č Ō œ */
  39. 0x0180, 0x0250, /* Latin Extended-B: Ǝ Ƹ */
  40. 0x0250, 0x02b0, /* IPA Extensions: ɐ ɔ ɘ ʌ ʍ */
  41. 0x0370, 0x0400, /* Greek and Coptic: Λ α β */
  42. 0x0400, 0x0500, /* Cyrillic: И Я */
  43. 0x0530, 0x0590, /* Armenian: Ո */
  44. 0x1401, 0x1677, /* Unified Canadian Aboriginal Syllabics: ᒐ ᗡ */
  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. 0x25a0, 0x2600, /* Geometric Shapes: ◆ ○ ● */
  53. 0x2600, 0x2700, /* Miscellaneous Symbols: ♥ ★ ☭ */
  54. 0x3000, 0x3040, /* CJK Symbols and Punctuation: 。「」 */
  55. 0x3040, 0x30a0, /* Hiragana: で す */
  56. 0x30a0, 0x3100, /* Katakana: ロ ル */
  57. 0xff00, 0xfff0, /* Halfwidth and Fullwidth Forms: A, B, C, a, b, c */
  58. 0x10400, 0x10450, /* Deseret: 𐐒 𐐋 */
  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(caca_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("/* libcaca 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 size_t const %s_size = %i;\n",
  163. prefix, 4 + control_size + data_size);
  164. printf("static uint8_t %s_data[%i] =\n",
  165. prefix, 4 + control_size + data_size);
  166. printf("{\n");
  167. printf("/* file: */\n");
  168. printf("0xCA,0xCA, /* caca_header */\n");
  169. written += 2;
  170. printf("'F','T', /* caca_file_type */\n");
  171. written += 2;
  172. printf("\n");
  173. printf("/* font_header: */\n");
  174. printf_u32("%s /* control_size */\n", control_size);
  175. printf_u32("%s /* data_size */\n", data_size);
  176. printf_u16("%s /* version */\n", 1);
  177. printf_u16("%s /* blocks */\n", blocks);
  178. printf_u32("%s /* glyphs */\n", glyphs);
  179. printf_u16("%s /* bpp */\n", bpp);
  180. printf_u16("%s /* std width */\n", stdwidth);
  181. printf_u16("%s /* std height */\n", height);
  182. printf_u16("%s /* max width */\n", fullwidth);
  183. printf_u16("%s /* max height */\n", height);
  184. printf_u16("%s /* flags */\n", 1);
  185. printf("\n");
  186. printf("/* block_info: */\n");
  187. n = 0;
  188. for(b = 0; blocklist[b + 1]; b += 2)
  189. {
  190. printf_u32("%s", blocklist[b]);
  191. printf_u32("%s", blocklist[b + 1]);
  192. printf_u32("%s\n", n);
  193. n += blocklist[b + 1] - blocklist[b];
  194. }
  195. printf("\n");
  196. /* Render all glyphs, so that we can know their offset */
  197. current_offset = n = 0;
  198. for(b = 0; blocklist[b + 1]; b += 2)
  199. {
  200. for(i = blocklist[b]; i < blocklist[b + 1]; i++)
  201. {
  202. int x, y, bytes, current_width = stdwidth;
  203. unsigned int k, current_size = stdsize;
  204. if(caca_utf32_is_fullwidth(i))
  205. {
  206. current_width = fullwidth;
  207. current_size = fullsize;
  208. }
  209. gtab[n].unicode = i;
  210. bytes = caca_utf32_to_utf8(gtab[n].buf, gtab[n].unicode);
  211. gtab[n].buf[bytes] = '\0';
  212. /* Render glyph on a bitmap */
  213. pango_layout_set_text(l, gtab[n].buf, -1);
  214. memset(img.buffer, 0, img.pitch * height);
  215. pango_ft2_render_layout(&img, l, 0, 0);
  216. /* Fix glyphs that we know how to handle better */
  217. fix_glyph(&img, gtab[n].unicode, current_width, height);
  218. /* Write bitmap as an escaped C string */
  219. memset(glyph_data + current_offset, 0, current_size);
  220. k = 0;
  221. for(y = 0; y < height; y++)
  222. {
  223. for(x = 0; x < current_width; x++)
  224. {
  225. uint8_t pixel = img.buffer[y * img.pitch + x];
  226. pixel >>= (8 - bpp);
  227. glyph_data[current_offset + k / 8]
  228. |= pixel << (8 - bpp - (k % 8));
  229. k += bpp;
  230. }
  231. }
  232. /* Check whether this is the same glyph as another one. Please
  233. * don't bullshit me about sorting, hashing and stuff like that,
  234. * our data is small enough for this to work. */
  235. for(k = 0; k < n; k++)
  236. {
  237. if(gtab[k].data_size != current_size)
  238. continue;
  239. #if 0
  240. if(!memcmp(glyph_data + gtab[k].data_offset,
  241. glyph_data + current_offset, current_size))
  242. break;
  243. #endif
  244. }
  245. gtab[n].data_offset = current_offset;
  246. gtab[n].data_width = current_width;
  247. gtab[n].data_size = current_size;
  248. gtab[n].same_as = k;
  249. if(k == n)
  250. current_offset += current_size;
  251. n++;
  252. }
  253. }
  254. printf("/* glyph_info: */\n");
  255. n = 0;
  256. for(b = 0; blocklist[b + 1]; b += 2)
  257. {
  258. for(i = blocklist[b]; i < blocklist[b + 1]; i++)
  259. {
  260. printf_u16("%s", gtab[n].data_width);
  261. printf_u16("%s", height);
  262. printf_u32("%s\n", gtab[gtab[n].same_as].data_offset);
  263. n++;
  264. }
  265. }
  266. printf("\n");
  267. printf("/* font_data: */\n");
  268. n = 0;
  269. for(b = 0; blocklist[b + 1]; b += 2)
  270. {
  271. for(i = blocklist[b]; i < blocklist[b + 1]; i++)
  272. {
  273. /* Print glyph value in comment */
  274. printf("/* ");
  275. printf_unicode(&gtab[n]);
  276. if(gtab[n].same_as == n)
  277. printf_hex(" */ %s\n",
  278. glyph_data + gtab[n].data_offset, gtab[n].data_size);
  279. else
  280. {
  281. printf(" is ");
  282. printf_unicode(&gtab[gtab[n].same_as]);
  283. printf(" */\n");
  284. }
  285. n++;
  286. }
  287. }
  288. printf("};\n");
  289. free(img.buffer);
  290. free(gtab);
  291. free(glyph_data);
  292. g_object_unref(l);
  293. g_object_unref(cx);
  294. return 0;
  295. }
  296. /*
  297. * XXX: the following functions are local
  298. */
  299. static void fix_glyph(FT_Bitmap *i, uint32_t ch,
  300. unsigned int width, unsigned int height)
  301. {
  302. unsigned int x, y;
  303. switch(ch)
  304. {
  305. case 0x00002580: /* ▀ */
  306. for(y = 0; y < height; y++)
  307. for(x = 0; x < width; x++)
  308. i->buffer[x + y * i->pitch] = y < height / 2 ? 0xff : 0x00;
  309. if(height & 1)
  310. for(x = 0; x < width; x++)
  311. i->buffer[x + (height / 2) * i->pitch] = 0x7f;
  312. break;
  313. case 0x00002584: /* ▄ */
  314. for(y = 0; y < height; y++)
  315. for(x = 0; x < width; x++)
  316. i->buffer[x + y * i->pitch] = y < height / 2 ? 0x00 : 0xff;
  317. if(height & 1)
  318. for(x = 0; x < width; x++)
  319. i->buffer[x + (height / 2) * i->pitch] = 0x7f;
  320. break;
  321. case 0x0000258c: /* ▌ */
  322. for(y = 0; y < height; y++)
  323. for(x = 0; x < width; x++)
  324. i->buffer[x + y * i->pitch] = x < width / 2 ? 0xff : 0x00;
  325. if(width & 1)
  326. for(y = 0; y < height; y++)
  327. i->buffer[(width / 2) + y * i->pitch] = 0x7f;
  328. break;
  329. case 0x00002590: /* ▐ */
  330. for(y = 0; y < height; y++)
  331. for(x = 0; x < width; x++)
  332. i->buffer[x + y * i->pitch] = x < width / 2 ? 0x00 : 0xff;
  333. if(width & 1)
  334. for(y = 0; y < height; y++)
  335. i->buffer[(width / 2) + y * i->pitch] = 0x7f;
  336. break;
  337. case 0x000025a0: /* ■ */
  338. for(y = 0; y < height; y++)
  339. for(x = 0; x < width; x++)
  340. i->buffer[x + y * i->pitch] =
  341. (y >= height / 4) && (y < 3 * height / 4) ? 0xff : 0x00;
  342. if(height & 3)
  343. for(x = 0; x < width; x++) /* FIXME: could be more precise */
  344. i->buffer[x + (height / 4) * i->pitch] =
  345. i->buffer[x + (3 * height / 4) * i->pitch] = 0x7f;
  346. break;
  347. case 0x00002588: /* █ */
  348. memset(i->buffer, 0xff, height * i->pitch);
  349. break;
  350. case 0x00002593: /* ▓ */
  351. for(y = 0; y < height; y++)
  352. for(x = 0; x < width; x++)
  353. i->buffer[x + y * i->pitch] =
  354. ((x + 2 * (y & 1)) & 3) ? 0xff : 0x00;
  355. break;
  356. case 0x00002592: /* ▒ */
  357. for(y = 0; y < height; y++)
  358. for(x = 0; x < width; x++)
  359. i->buffer[x + y * i->pitch] = ((x + y) & 1) ? 0xff : 0x00;
  360. break;
  361. case 0x00002591: /* ░ */
  362. for(y = 0; y < height; y++)
  363. for(x = 0; x < width; x++)
  364. i->buffer[x + y * i->pitch] =
  365. ((x + 2 * (y & 1)) & 3) ? 0x00 : 0xff;
  366. break;
  367. }
  368. }
  369. static int printf_unicode(struct glyph *g)
  370. {
  371. int wr = 0;
  372. wr += printf("U+%.04X: \"", g->unicode);
  373. if(g->unicode < 0x20 || (g->unicode >= 0x7f && g->unicode <= 0xa0))
  374. wr += printf("\\x%.02x\"", g->unicode);
  375. else
  376. wr += printf("%s\"", g->buf);
  377. return wr;
  378. }
  379. static int printf_u32(char const *fmt, uint32_t i)
  380. {
  381. uint32_t ni = hton32(i);
  382. return printf_hex(fmt, (uint8_t *)&ni, 4);
  383. }
  384. static int printf_u16(char const *fmt, uint16_t i)
  385. {
  386. uint16_t ni = hton16(i);
  387. return printf_hex(fmt, (uint8_t *)&ni, 2);
  388. }
  389. static int printf_hex(char const *fmt, uint8_t *data, int bytes)
  390. {
  391. char buf[BUFSIZ];
  392. char *parser = buf;
  393. while(bytes--)
  394. parser += sprintf(parser, "%i,", (unsigned int)*data++);
  395. parser[0] = '\0';
  396. return printf(fmt, buf);
  397. }