PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
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.

512 lines
13KB

  1. /* Convert BDF format font data to ILI9341_t3 packed format
  2. Copyright 2015 - Paul Stoffregen <paul@pjrc.com>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <stdint.h>
  17. #include <stdarg.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #define ENCODING_START 32
  21. #define ENCODING_END 126
  22. //#define ENCODING_OFFSET 0xF000 // intended for Font-Awesome
  23. char font_name[1024] = "myFont";
  24. //int ascii_art = 1; // ;-)
  25. int ascii_art = 0; // :-(
  26. typedef struct {
  27. int width;
  28. int height;
  29. int xoffset;
  30. int yoffset;
  31. int delta;
  32. int encoding;
  33. int byteoffset;
  34. const uint8_t *data;
  35. } glyph_t;
  36. glyph_t glyphs[ENCODING_END+1];
  37. int bits_width, bits_height, bits_delta;
  38. int bits_xoffset, bits_yoffset, bits_index;
  39. int font_size = 0;
  40. int line_space = 0;
  41. int cap_height = 0;
  42. int is_bold = 0;
  43. int is_italic = 0;
  44. void parse_bdf(FILE *fp, glyph_t *g);
  45. void compute_min_max(void);
  46. int bits_required_unsigned(int max);
  47. int bits_required_signed(int min, int max);
  48. void die(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
  49. static uint8_t hex1(const char c);
  50. static uint8_t hex2(const char *str);
  51. int pixel(const glyph_t *g, int x, int y)
  52. {
  53. uint8_t b;
  54. if (x >= g->width) return 0;
  55. if (y >= g->height) return 0;
  56. b = g->data[(((g->width + 7) >> 3) * y) + (x >> 3)];
  57. if (b & (1 << (7 - (x & 7)))) return 1;
  58. return 0;
  59. }
  60. void print_glyph(const glyph_t *g)
  61. {
  62. int x, y;
  63. printf("/* ");
  64. printf("Glyph %d: ", g->encoding);
  65. printf("size=%dx%d, ", g->width, g->height);
  66. printf("offset=%d,%d, ", g->xoffset, g->yoffset);
  67. printf("delta=%d\n", g->delta);
  68. for (y=0; y < g->height; y++) {
  69. printf("\t");
  70. for (x=0; x < g->width; x++) {
  71. printf("%c", pixel(g, x, y) ? '*' : ' ');
  72. }
  73. printf("\n");
  74. }
  75. printf("*/\n");
  76. }
  77. uint8_t output_state_byte;
  78. uint8_t output_state_bitcount = 0;
  79. uint8_t output_state_linelen = 0;
  80. int output_state_bytecount = 0;
  81. void output_newline(void)
  82. {
  83. if (output_state_linelen > 0) {
  84. printf("\n");
  85. output_state_linelen = 0;
  86. }
  87. }
  88. void output_bit(int bit)
  89. {
  90. uint8_t bitmask = 1 << (7 - output_state_bitcount);
  91. if (bit) {
  92. //printf("(1)");
  93. output_state_byte |= bitmask;
  94. } else {
  95. //printf("(0)");
  96. output_state_byte &= ~bitmask;
  97. }
  98. output_state_bitcount++;
  99. if (output_state_bitcount >= 8) {
  100. output_state_bitcount = 0;
  101. printf("0x%02X,", output_state_byte);
  102. output_state_bytecount++;
  103. if (++output_state_linelen >= 10) output_newline();
  104. output_state_byte = 0;
  105. }
  106. }
  107. void output_number(int num, int bits)
  108. {
  109. while (bits > 0) {
  110. output_bit(num & (1 << (bits -1)));
  111. bits--;
  112. }
  113. //printf("\n");
  114. }
  115. void output_line(const glyph_t *g, int y)
  116. {
  117. int x;
  118. for (x=0; x < g->width; x++) {
  119. output_bit(pixel(g, x, y));
  120. }
  121. //printf("\n");
  122. }
  123. void output_pad_to_byte(void)
  124. {
  125. while (output_state_bitcount > 0) output_bit(0);
  126. //printf("\n");
  127. }
  128. int lines_identical(const glyph_t *g, int y1, int y2)
  129. {
  130. int x;
  131. for (x=0; x < g->width; x++) {
  132. if (pixel(g, x, y1) != pixel(g, x, y2)) return 0;
  133. }
  134. return 1;
  135. }
  136. int num_lines_identical(const glyph_t *g, int y)
  137. {
  138. int y2;
  139. for (y2 = y+1; y2 < g->height; y2++) {
  140. if (!lines_identical(g, y, y2)) break;
  141. }
  142. return y2 - y - 1;
  143. }
  144. void output_glyph(const glyph_t *g)
  145. {
  146. int y = 0;
  147. int identical_count;
  148. //printf("output glyph:");
  149. if (ascii_art) print_glyph(g);
  150. output_number(0, 3); // reserved bits, intended to identify future formats
  151. output_number(g->width, bits_width);
  152. output_number(g->height, bits_height);
  153. output_number(g->xoffset, bits_xoffset);
  154. output_number(g->yoffset, bits_yoffset);
  155. output_number(g->delta, bits_delta);
  156. while (y < g->height) {
  157. //printf("line %d: ", y);
  158. identical_count = num_lines_identical(g, y);
  159. if (identical_count == 0) {
  160. //printf("unique\n");
  161. output_bit(0);
  162. output_line(g, y);
  163. } else {
  164. output_bit(1);
  165. if (identical_count > 6) identical_count = 6;
  166. //printf("duplicate %d times\n", identical_count);
  167. output_number(identical_count - 1, 3);
  168. output_line(g, y);
  169. y += identical_count;
  170. }
  171. y++;
  172. }
  173. output_pad_to_byte();
  174. if (ascii_art) output_newline();
  175. }
  176. int main()
  177. {
  178. glyph_t *g;
  179. int datasize, indexsize;
  180. memset(glyphs, 0, sizeof(glyphs));
  181. parse_bdf(stdin, glyphs);
  182. //for (i=32; i<48; i++) print_glyph(glyphs + i);
  183. compute_min_max();
  184. printf("static const unsigned char %s_data[] = {\n", font_name);
  185. for (g = glyphs + ENCODING_START; g <= glyphs + ENCODING_END; g++) {
  186. g->byteoffset = output_state_bytecount;
  187. output_glyph(g);
  188. //printf("// offset = %d\n", output_state_bytecount);
  189. }
  190. output_newline();
  191. printf("};\n");
  192. datasize = output_state_bytecount;
  193. printf("/* font data size: %d bytes */\n\n", datasize);
  194. bits_index = bits_required_unsigned(output_state_bytecount);
  195. printf("static const unsigned char %s_index[] = {\n", font_name);
  196. for (g = glyphs + ENCODING_START; g <= glyphs + ENCODING_END; g++) {
  197. output_number(g->byteoffset, bits_index);
  198. }
  199. output_pad_to_byte();
  200. output_newline();
  201. printf("};\n");
  202. indexsize = output_state_bytecount - datasize;
  203. printf("/* font index size: %d bytes */\n\n", indexsize);
  204. if (ascii_art) {
  205. printf("/*\n");
  206. printf("typedef struct {\n");
  207. printf("\tconst unsigned char *index;\n");
  208. printf("\tconst unsigned char *unicode;\n");
  209. printf("\tconst unsigned char *data;\n");
  210. printf("\tunsigned char version;\n");
  211. printf("\tunsigned char reserved;\n");
  212. printf("\tunsigned char index1_first;\n");
  213. printf("\tunsigned char index1_last;\n");
  214. printf("\tunsigned char index2_first;\n");
  215. printf("\tunsigned char index2_last;\n");
  216. printf("\tunsigned char bits_index;\n");
  217. printf("\tunsigned char bits_width;\n");
  218. printf("\tunsigned char bits_height;\n");
  219. printf("\tunsigned char bits_xoffset;\n");
  220. printf("\tunsigned char bits_yoffset;\n");
  221. printf("\tunsigned char bits_delta;\n");
  222. printf("\tunsigned char line_space;\n");
  223. printf("\tunsigned char cap_height;\n");
  224. printf("} ILI9341_t3_font_t;\n");
  225. printf("*/\n");
  226. }
  227. printf("const ILI9341_t3_font_t %s = {\n", font_name);
  228. printf("\t%s_index,\n", font_name);
  229. printf("\t0,\n");
  230. printf("\t%s_data,\n", font_name);
  231. printf("\t1,\n");
  232. printf("\t0,\n");
  233. printf("\t%d,\n", ENCODING_START);
  234. printf("\t%d,\n", ENCODING_END);
  235. printf("\t0,\n");
  236. printf("\t0,\n");
  237. printf("\t%d,\n", bits_index);
  238. printf("\t%d,\n", bits_width);
  239. printf("\t%d,\n", bits_height);
  240. printf("\t%d,\n", bits_xoffset);
  241. printf("\t%d,\n", bits_yoffset);
  242. printf("\t%d,\n", bits_delta);
  243. printf("\t%d,\n", line_space);
  244. printf("\t%d\n", cap_height);
  245. printf("};\n");
  246. printf("\n\n\n");
  247. return 0;
  248. }
  249. void parse_bdf(FILE *fp, glyph_t *g)
  250. {
  251. char line[1024], name[1024], *src, *dst;
  252. const char *p;
  253. int state = 0, linenum = 0;
  254. int found_encoding = -1, found_dwidth = -1, found_bbx = -1;
  255. int found_ascent = 0, found_descent = 0;
  256. int expect_lines, expect_bytes;
  257. int encoding, dwidth_x, dwidth_y, bbx_width, bbx_height, bbx_xoffset, bbx_yoffset;
  258. int size, font_ascent = 0, font_descent = 0;
  259. uint8_t *data;
  260. int i, j;
  261. while (fgets(line, sizeof(line), fp)) {
  262. linenum++;
  263. if (state == 0) {
  264. if (strncmp(line, "STARTCHAR", 10) == 0) {
  265. //printf("startchar\n");
  266. found_encoding = 0;
  267. found_dwidth = 0;
  268. found_bbx = 0;
  269. continue;
  270. }
  271. if (sscanf(line, "SIZE %d %d %d", &size, &i, &j) == 3) {
  272. font_size = size;
  273. }
  274. if (sscanf(line, "FAMILY_NAME \"%[^\"]\"", name) == 1) {
  275. //printf("// name = %s\n", name);
  276. src = name;
  277. dst = font_name;
  278. while (*src) {
  279. if (isalnum(*src)) *dst++ = *src;
  280. src++;
  281. }
  282. *dst = 0;
  283. }
  284. if (strncmp(line, "WEIGHT_NAME \"Bold\"", 18) == 0) {
  285. is_bold = 1;
  286. }
  287. if (strncmp(line, "SLANT \"I\"", 9) == 0) {
  288. is_italic = 1;
  289. }
  290. if (sscanf(line, "FONT_ASCENT %d", &font_ascent) == 1) {
  291. found_ascent = 1;
  292. }
  293. if (sscanf(line, "FONT_DESCENT %d", &font_descent) == 1) {
  294. found_descent = 1;
  295. }
  296. if (sscanf(line, "ENCODING %d", &encoding) == 1) {
  297. //printf("encoding %d\n", encoding);
  298. found_encoding = 1;
  299. #ifdef ENCODING_OFFSET
  300. if (encoding >= ENCODING_OFFSET + ENCODING_START
  301. && encoding <= ENCODING_OFFSET + ENCODING_END) {
  302. encoding -= ENCODING_OFFSET;
  303. } else {
  304. encoding = ENCODING_OFFSET + ENCODING_END + 1;
  305. }
  306. #endif
  307. continue;
  308. }
  309. if (sscanf(line, "DWIDTH %d %d", &dwidth_x, &dwidth_y) == 2) {
  310. //printf("dwidth %d %d\n", dwidth_x, dwidth_y);
  311. if (dwidth_x < 0) {
  312. die("DWIDTH x negative, at line %d", linenum);
  313. }
  314. if (dwidth_y != 0) {
  315. die("DWIDTH y not zero, at line %d", linenum);
  316. }
  317. found_dwidth = 1;
  318. continue;
  319. }
  320. if (sscanf(line, "BBX %d %d %d %d", &bbx_width,
  321. &bbx_height, &bbx_xoffset, &bbx_yoffset) == 4) {
  322. //printf("bbx %d %d %d %d\n",
  323. //bbx_width, bbx_height, bbx_xoffset, bbx_yoffset);
  324. if (bbx_width < 0) die("BBX width negative, line %d", linenum);
  325. if (bbx_height < 0) die("BBX height negative, line %d", linenum);
  326. found_bbx = 1;
  327. continue;
  328. }
  329. if (strncmp(line, "BITMAP", 6) == 0) {
  330. if (found_encoding != 1) die("missing ENCODING, line %d", linenum);
  331. if (found_dwidth != 1) die("missing DWIDTH, line %d", linenum);
  332. if (found_bbx != 1) die("missing BBX, line %d", linenum);
  333. expect_lines = bbx_height;
  334. expect_bytes = (bbx_width + 7) >> 3;
  335. if (encoding >= ENCODING_START && encoding <= ENCODING_END) {
  336. data = malloc(expect_lines * expect_bytes);
  337. if (!data) die("unable to allocate memory!");
  338. g[encoding].width = bbx_width;
  339. g[encoding].height = bbx_height;
  340. g[encoding].xoffset = bbx_xoffset;
  341. g[encoding].yoffset = bbx_yoffset;
  342. g[encoding].delta = dwidth_x;
  343. g[encoding].encoding = encoding;
  344. g[encoding].data = data;
  345. } else {
  346. data = NULL;
  347. }
  348. state = 1;
  349. continue;
  350. }
  351. } else {
  352. if (expect_lines > 0 && expect_bytes > 0) {
  353. p = line;
  354. for (i=0; i < expect_bytes; i++) {
  355. if (isxdigit(p[0]) && isxdigit(p[1])) {
  356. if (data) *data++ = hex2(p);
  357. } else {
  358. die("non-hex char on line %d", linenum);
  359. }
  360. p += 2;
  361. }
  362. expect_lines--;
  363. } else {
  364. if (strncmp(line, "ENDCHAR", 7) == 0) {
  365. state = 0;
  366. } else {
  367. die("expected ENDCHAR at line %d", linenum);
  368. }
  369. }
  370. }
  371. }
  372. if (found_ascent && found_descent) {
  373. line_space = font_ascent + font_descent;
  374. //printf("// line_space = %d\n", line_space);
  375. }
  376. if (ENCODING_START <= 'E' && ENCODING_END >= 'E' && g['E'].data != NULL) {
  377. cap_height = g['E'].height + g['E'].yoffset;
  378. //printf("// cap_height = %d\n", cap_height);
  379. }
  380. sprintf(name, "_%d", font_size);
  381. strcat(font_name, name);
  382. if (is_bold) strcat(font_name, "_Bold");
  383. if (is_italic) strcat(font_name, "_Italic");
  384. }
  385. static uint8_t hex1(const char c)
  386. {
  387. uint8_t b = 0;
  388. if (c >= '0' && c <= '9') {
  389. b = c - '0';
  390. } else if (c >= 'A' && c <= 'F') {
  391. b = c - 'A' + 10;
  392. } else if (c >= 'a' && c <= 'f') {
  393. b = c - 'a' + 10;
  394. }
  395. return b;
  396. }
  397. static uint8_t hex2(const char *str)
  398. {
  399. return (hex1(str[0]) << 4) | hex1(str[1]);
  400. }
  401. int bits_required_unsigned(int max)
  402. {
  403. int n = 1;
  404. if (max < 0) max = 0;
  405. while (max >= (1 << n)) n++;
  406. return n;
  407. }
  408. int bits_required_signed(int min, int max)
  409. {
  410. int n = 2;
  411. if (min > 0) min = 0;
  412. if (max < 0) max = 0;
  413. while (min < -(1 << (n-1))) n++;
  414. while (max >= (1 << (n-1))) n++;
  415. return n;
  416. }
  417. void compute_min_max(void)
  418. {
  419. int max_width=0, max_height=0, max_delta=0;
  420. int min_xoffset=0, max_xoffset=0, min_yoffset=0, max_yoffset=0;
  421. glyph_t *g;
  422. for (g = glyphs + ENCODING_START; g <= glyphs + ENCODING_END; g++) {
  423. if (g->encoding == 0) g->encoding = g - glyphs;
  424. //printf("%d\n", g->encoding);
  425. if (g->width > max_width) max_width = g->width;
  426. if (g->height > max_height) max_height = g->height;
  427. if (g->xoffset < min_xoffset) min_xoffset = g->xoffset;
  428. if (g->xoffset > max_xoffset) max_xoffset = g->xoffset;
  429. if (g->yoffset < min_yoffset) min_yoffset = g->yoffset;
  430. if (g->yoffset > max_yoffset) max_yoffset = g->yoffset;
  431. if (g->delta > max_delta) max_delta = g->delta;
  432. }
  433. bits_width = bits_required_unsigned(max_width);
  434. bits_height = bits_required_unsigned(max_height);
  435. bits_xoffset = bits_required_signed(min_xoffset, max_xoffset);
  436. bits_yoffset = bits_required_signed(min_yoffset, max_yoffset);
  437. bits_delta = bits_required_unsigned(max_delta);
  438. //printf("width range 0 to %d --> %d bits\n", max_width, bits_width);
  439. //printf("height range 0 to %d --> %d bits\n", max_height, bits_height);
  440. //printf("xoffset range %d to %d --> %d bits\n", min_xoffset, max_xoffset, bits_xoffset);
  441. //printf("yoffset range %d to %d --> %d bits\n", min_yoffset, max_yoffset, bits_yoffset);
  442. //printf("delta 0 to %d --> %d bits\n", max_delta, bits_delta);
  443. }
  444. void die(const char *format, ...)
  445. {
  446. va_list args;
  447. va_start(args, format);
  448. //fprintf(stderr, "bdf_to_ili9341: ");
  449. vfprintf(stderr, format, args);
  450. exit(1);
  451. }