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.
 
 
 
 
 
 

320 lines
8.8 KiB

  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 <pango/pango.h>
  27. #include <pango/pangoft2.h>
  28. static int const blocklist[] =
  29. {
  30. 0x0000, 0x0080, /* Basic latin: A, B, C, a, img, c */
  31. 0x0080, 0x0100, /* Latin-1 Supplement: Ä, Ç, å, ß */
  32. 0x0100, 0x0180, /* Latin Extended-A: Ā č Ō œ */
  33. 0x0180, 0x0250, /* Latin Extended-B: Ǝ Ƹ */
  34. 0x0250, 0x02b0, /* IPA Extensions: ɐ ɔ ɘ ʌ ʍ */
  35. 0x0370, 0x0400, /* Greek and Coptic: Λ α β */
  36. 0x0400, 0x0500, /* Cyrillic: И Я */
  37. 0x2000, 0x2070, /* General Punctuation: ‘’ “” */
  38. #if 0
  39. 0x2100, 0x2150, /* Letterlike Symbols: Ⅎ */
  40. #endif
  41. 0x2300, 0x2400, /* Miscellaneous Technical: ⌂ */
  42. 0x2500, 0x2580, /* Box Drawing: ═ ║ ╗ ╔ ╩ */
  43. 0x2580, 0x25a0, /* Block Elements: ▛ ▞ ░ ▒ ▓ */
  44. 0, 0
  45. };
  46. static int printf_hex(char const *, uint8_t *, int);
  47. static int printf_u32(char const *, uint32_t);
  48. static int printf_u16(char const *, uint16_t);
  49. int main(int argc, char *argv[])
  50. {
  51. PangoContext *cx;
  52. PangoFontDescription *fd;
  53. PangoFontMap *fm;
  54. PangoLayout *l;
  55. PangoRectangle r;
  56. FT_Bitmap img;
  57. int width, height, b, i, n, blocks, glyphs;
  58. unsigned int glyph_size, control_size, data_size;
  59. uint8_t *glyph_data;
  60. unsigned int bpp, dpi;
  61. char const *prefix, *font;
  62. if(argc != 5)
  63. {
  64. fprintf(stderr, "%s: wrong argument count\n", argv[0]);
  65. fprintf(stderr, "usage: %s <prefix> <font> <dpi> <bpp>\n", argv[0]);
  66. fprintf(stderr, "eg: %s monospace9 \"Monospace 9\" 96 4\n", argv[0]);
  67. return -1;
  68. }
  69. prefix = argv[1];
  70. font = argv[2];
  71. dpi = atoi(argv[3]);
  72. bpp = atoi(argv[4]);
  73. if(dpi == 0 || (bpp != 1 && bpp != 2 && bpp != 4 && bpp != 8))
  74. {
  75. fprintf(stderr, "%s: invalid argument\n", argv[0]);
  76. return -1;
  77. }
  78. fprintf(stderr, "Font \"%s\", %i dpi, %i bpp\n", font, dpi, bpp);
  79. /* Initialise Pango */
  80. fm = pango_ft2_font_map_new();
  81. pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fm), dpi, dpi);
  82. cx = pango_ft2_font_map_create_context(PANGO_FT2_FONT_MAP(fm));
  83. l = pango_layout_new(cx);
  84. if(!l)
  85. {
  86. fprintf(stderr, "%s: unable to initialise pango\n", argv[0]);
  87. g_object_unref(cx);
  88. return -1;
  89. }
  90. fd = pango_font_description_from_string(font);
  91. pango_layout_set_font_description(l, fd);
  92. pango_font_description_free(fd);
  93. /* Initialise our FreeType2 bitmap */
  94. img.width = 256;
  95. img.pitch = 256;
  96. img.rows = 256;
  97. img.buffer = malloc(256 * 256);
  98. img.num_grays = 256;
  99. img.pixel_mode = ft_pixel_mode_grays;
  100. /* Test rendering so that we know the glyph width */
  101. pango_layout_set_markup(l, "@", -1);
  102. pango_layout_get_extents(l, NULL, &r);
  103. width = PANGO_PIXELS(r.width);
  104. height = PANGO_PIXELS(r.height);
  105. glyph_size = ((width * height) + (8 / bpp) - 1) / (8 / bpp);
  106. glyph_data = malloc(glyph_size);
  107. /* Compute blocks and glyphs count */
  108. blocks = 0;
  109. glyphs = 0;
  110. for(b = 0; blocklist[b + 1]; b += 2)
  111. {
  112. blocks++;
  113. glyphs += blocklist[b + 1] - blocklist[b];
  114. }
  115. control_size = 24 + 12 * blocks + 8 * glyphs;
  116. data_size = glyph_size * glyphs;
  117. /* Let's go! */
  118. printf("/* libcucul font file\n");
  119. printf(" * \"%s\": %i dpi, %i bpp, %ix%i glyphs\n",
  120. font, dpi, bpp, width, height);
  121. printf(" * Automatically generated by tools/makefont.c:\n");
  122. printf(" * tools/makefont %s \"%s\" %i %i\n", prefix, font, dpi, bpp);
  123. printf(" */\n");
  124. printf("\n");
  125. printf("static unsigned int const %s_size = %i;\n",
  126. prefix, 8 + control_size + data_size);
  127. printf("static unsigned char const %s_data[] =\n", prefix);
  128. printf("/* file: */\n");
  129. printf("\"CACA\" /* caca_header */\n");
  130. printf("\"FONT\" /* caca_file_type */\n");
  131. printf("\n");
  132. printf("/* font_header: */\n");
  133. printf_u32("\"%s\" /* control_size */\n", control_size);
  134. printf_u32("\"%s\" /* data_size */\n", data_size);
  135. printf_u16("\"%s\" /* version */\n", 1);
  136. printf_u16("\"%s\" /* blocks */\n", blocks);
  137. printf_u32("\"%s\" /* glyphs */\n", glyphs);
  138. printf_u16("\"%s\" /* bpp */\n", bpp);
  139. printf_u16("\"%s\" /* width */\n", width);
  140. printf_u16("\"%s\" /* height */\n", height);
  141. printf_u16("\"%s\" /* flags */\n", 1);
  142. printf("\n");
  143. printf("/* block_info: */\n");
  144. n = 0;
  145. for(b = 0; blocklist[b + 1]; b += 2)
  146. {
  147. printf_u32("\"%s", blocklist[b]);
  148. printf_u32("%s", blocklist[b + 1]);
  149. printf_u32("%s\"\n", n);
  150. n += blocklist[b + 1] - blocklist[b];
  151. }
  152. printf("\n");
  153. printf("/* glyph_info: */\n");
  154. n = 0;
  155. for(b = 0; blocklist[b + 1]; b += 2)
  156. {
  157. for(i = blocklist[b]; i < blocklist[b + 1]; i++)
  158. {
  159. printf_u16("\"%s", width);
  160. printf_u16("%s", height);
  161. printf_u32("%s\"\n", n * glyph_size);
  162. n++;
  163. }
  164. }
  165. printf("\n");
  166. printf("/* font_data: */\n");
  167. for(b = 0; blocklist[b + 1]; b += 2)
  168. {
  169. for(i = blocklist[b]; i < blocklist[b + 1]; i++)
  170. {
  171. unsigned int ch = i;
  172. char buf[10], *parser;
  173. int x, y, bytes;
  174. if(ch < 0x80)
  175. {
  176. bytes = 1;
  177. buf[0] = ch;
  178. buf[1] = '\0';
  179. }
  180. else
  181. {
  182. static const unsigned char mark[7] =
  183. {
  184. 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
  185. };
  186. /* FIXME: use libcucul instead of this shit */
  187. bytes = (ch < 0x800) ? 2 : (ch < 0x10000) ? 3 : 4;
  188. buf[bytes] = '\0';
  189. parser = buf + bytes;
  190. switch(bytes)
  191. {
  192. case 4: *--parser = (ch | 0x80) & 0xbf; ch >>= 6;
  193. case 3: *--parser = (ch | 0x80) & 0xbf; ch >>= 6;
  194. case 2: *--parser = (ch | 0x80) & 0xbf; ch >>= 6;
  195. }
  196. *--parser = ch | mark[bytes];
  197. }
  198. /* Print glyph value in comment */
  199. printf("/* U+%.04X: \"", i);
  200. if(i < 0x20 || (i >= 0x80 && i <= 0xa0))
  201. printf("\\x%.02x\" */", i);
  202. else
  203. printf("%s\" */ ", buf);
  204. /* Render glyph on a bitmap */
  205. pango_layout_set_text(l, buf, -1);
  206. memset(glyph_data, 0, glyph_size);
  207. memset(img.buffer, 0, img.pitch * height);
  208. pango_ft2_render_layout(&img, l, 0, 0);
  209. /* Write bitmap as an escaped C string */
  210. n = 0;
  211. for(y = 0; y < height; y++)
  212. {
  213. for(x = 0; x < width; x++)
  214. {
  215. uint8_t pixel = img.buffer[y * img.pitch + x];
  216. pixel >>= (8 - bpp);
  217. glyph_data[n / 8] |= pixel << (8 - bpp - (n % 8));
  218. n += bpp;
  219. }
  220. }
  221. printf_hex("\"%s\"\n", glyph_data, glyph_size);
  222. }
  223. }
  224. printf(";\n");
  225. free(img.buffer);
  226. g_object_unref(l);
  227. g_object_unref(cx);
  228. return 0;
  229. }
  230. /*
  231. * XXX: the following functions are local
  232. */
  233. static int printf_u32(char const *fmt, uint32_t i)
  234. {
  235. uint32_t ni = htonl(i);
  236. return printf_hex(fmt, (uint8_t *)&ni, 4);
  237. }
  238. static int printf_u16(char const *fmt, uint16_t i)
  239. {
  240. uint16_t ni = htons(i);
  241. return printf_hex(fmt, (uint8_t *)&ni, 2);
  242. }
  243. static int printf_hex(char const *fmt, uint8_t *data, int bytes)
  244. {
  245. char buf[BUFSIZ];
  246. char *parser = buf;
  247. int rewind = 0; /* we use this variable to rewind 2 bytes after \000
  248. * was printed when the next char starts with "\", too. */
  249. while(bytes--)
  250. {
  251. uint8_t ch = *data++;
  252. if(ch == '\\' || ch == '"')
  253. {
  254. parser -= rewind;
  255. parser += sprintf(parser, "\\%c", ch);
  256. rewind = 0;
  257. }
  258. else if(ch >= 0x20 && ch < 0x7f)
  259. {
  260. parser += sprintf(parser, "%c", ch);
  261. rewind = 0;
  262. }
  263. else
  264. {
  265. parser -= rewind;
  266. parser += sprintf(parser, "\\%.03o", ch);
  267. rewind = ch ? 0 : 2;
  268. }
  269. }
  270. parser -= rewind;
  271. parser[0] = '\0';
  272. return printf(fmt, buf);
  273. }