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.
 
 
 
 
 
 

475 line
14 KiB

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