fontconvert.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. TrueType to Adafruit_GFX font converter. Derived from Peter Jakobs'
  3. Adafruit_ftGFX fork & makefont tool, and Paul Kourany's Adafruit_mfGFX.
  4. NOT AN ARDUINO SKETCH. This is a command-line tool for preprocessing
  5. fonts to be used with the Adafruit_GFX Arduino library.
  6. For UNIX-like systems. Outputs to stdout; redirect to header file, e.g.:
  7. ./fontconvert ~/Library/Fonts/FreeSans.ttf 18 > FreeSans18pt7b.h
  8. REQUIRES FREETYPE LIBRARY. www.freetype.org
  9. Currently this only extracts the printable 7-bit ASCII chars of a font.
  10. Will eventually extend with some int'l chars a la ftGFX, not there yet.
  11. Keep 7-bit fonts around as an option in that case, more compact.
  12. See notes at end for glyph nomenclature & other tidbits.
  13. */
  14. #ifndef ARDUINO
  15. #include <ctype.h>
  16. #include <ft2build.h>
  17. #include <stdint.h>
  18. #include <stdio.h>
  19. #include FT_GLYPH_H
  20. #include FT_MODULE_H
  21. #include FT_TRUETYPE_DRIVER_H
  22. #include "../gfxfont.h" // Adafruit_GFX font structures
  23. #define DPI 141 // Approximate res. of Adafruit 2.8" TFT
  24. // Accumulate bits for output, with periodic hexadecimal byte write
  25. void enbit(uint8_t value) {
  26. static uint8_t row = 0, sum = 0, bit = 0x80, firstCall = 1;
  27. if (value)
  28. sum |= bit; // Set bit if needed
  29. if (!(bit >>= 1)) { // Advance to next bit, end of byte reached?
  30. if (!firstCall) { // Format output table nicely
  31. if (++row >= 12) { // Last entry on line?
  32. printf(",\n "); // Newline format output
  33. row = 0; // Reset row counter
  34. } else { // Not end of line
  35. printf(", "); // Simple comma delim
  36. }
  37. }
  38. printf("0x%02X", sum); // Write byte value
  39. sum = 0; // Clear for next byte
  40. bit = 0x80; // Reset bit counter
  41. firstCall = 0; // Formatting flag
  42. }
  43. }
  44. int main(int argc, char *argv[]) {
  45. int i, j, err, size, first = ' ', last = '~', bitmapOffset = 0, x, y, byte;
  46. char *fontName, c, *ptr;
  47. FT_Library library;
  48. FT_Face face;
  49. FT_Glyph glyph;
  50. FT_Bitmap *bitmap;
  51. FT_BitmapGlyphRec *g;
  52. GFXglyph *table;
  53. uint8_t bit;
  54. // Parse command line. Valid syntaxes are:
  55. // fontconvert [filename] [size]
  56. // fontconvert [filename] [size] [last char]
  57. // fontconvert [filename] [size] [first char] [last char]
  58. // Unless overridden, default first and last chars are
  59. // ' ' (space) and '~', respectively
  60. if (argc < 3) {
  61. fprintf(stderr, "Usage: %s fontfile size [first] [last]\n", argv[0]);
  62. return 1;
  63. }
  64. size = atoi(argv[2]);
  65. if (argc == 4) {
  66. last = atoi(argv[3]);
  67. } else if (argc == 5) {
  68. first = atoi(argv[3]);
  69. last = atoi(argv[4]);
  70. }
  71. if (last < first) {
  72. i = first;
  73. first = last;
  74. last = i;
  75. }
  76. ptr = strrchr(argv[1], '/'); // Find last slash in filename
  77. if (ptr)
  78. ptr++; // First character of filename (path stripped)
  79. else
  80. ptr = argv[1]; // No path; font in local dir.
  81. // Allocate space for font name and glyph table
  82. if ((!(fontName = malloc(strlen(ptr) + 20))) ||
  83. (!(table = (GFXglyph *)malloc((last - first + 1) * sizeof(GFXglyph))))) {
  84. fprintf(stderr, "Malloc error\n");
  85. return 1;
  86. }
  87. // Derive font table names from filename. Period (filename
  88. // extension) is truncated and replaced with the font size & bits.
  89. strcpy(fontName, ptr);
  90. ptr = strrchr(fontName, '.'); // Find last period (file ext)
  91. if (!ptr)
  92. ptr = &fontName[strlen(fontName)]; // If none, append
  93. // Insert font size and 7/8 bit. fontName was alloc'd w/extra
  94. // space to allow this, we're not sprintfing into Forbidden Zone.
  95. sprintf(ptr, "%dpt%db", size, (last > 127) ? 8 : 7);
  96. // Space and punctuation chars in name replaced w/ underscores.
  97. for (i = 0; (c = fontName[i]); i++) {
  98. if (isspace(c) || ispunct(c))
  99. fontName[i] = '_';
  100. }
  101. // Init FreeType lib, load font
  102. if ((err = FT_Init_FreeType(&library))) {
  103. fprintf(stderr, "FreeType init error: %d", err);
  104. return err;
  105. }
  106. // Use TrueType engine version 35, without subpixel rendering.
  107. // This improves clarity of fonts since this library does not
  108. // support rendering multiple levels of gray in a glyph.
  109. // See https://github.com/adafruit/Adafruit-GFX-Library/issues/103
  110. FT_UInt interpreter_version = TT_INTERPRETER_VERSION_35;
  111. FT_Property_Set(library, "truetype", "interpreter-version",
  112. &interpreter_version);
  113. if ((err = FT_New_Face(library, argv[1], 0, &face))) {
  114. fprintf(stderr, "Font load error: %d", err);
  115. FT_Done_FreeType(library);
  116. return err;
  117. }
  118. // << 6 because '26dot6' fixed-point format
  119. FT_Set_Char_Size(face, size << 6, 0, DPI, 0);
  120. // Currently all symbols from 'first' to 'last' are processed.
  121. // Fonts may contain WAY more glyphs than that, but this code
  122. // will need to handle encoding stuff to deal with extracting
  123. // the right symbols, and that's not done yet.
  124. // fprintf(stderr, "%ld glyphs\n", face->num_glyphs);
  125. printf("const uint8_t %sBitmaps[] PROGMEM = {\n ", fontName);
  126. // Process glyphs and output huge bitmap data array
  127. for (i = first, j = 0; i <= last; i++, j++) {
  128. // MONO renderer provides clean image with perfect crop
  129. // (no wasted pixels) via bitmap struct.
  130. if ((err = FT_Load_Char(face, i, FT_LOAD_TARGET_MONO))) {
  131. fprintf(stderr, "Error %d loading char '%c'\n", err, i);
  132. continue;
  133. }
  134. if ((err = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO))) {
  135. fprintf(stderr, "Error %d rendering char '%c'\n", err, i);
  136. continue;
  137. }
  138. if ((err = FT_Get_Glyph(face->glyph, &glyph))) {
  139. fprintf(stderr, "Error %d getting glyph '%c'\n", err, i);
  140. continue;
  141. }
  142. bitmap = &face->glyph->bitmap;
  143. g = (FT_BitmapGlyphRec *)glyph;
  144. // Minimal font and per-glyph information is stored to
  145. // reduce flash space requirements. Glyph bitmaps are
  146. // fully bit-packed; no per-scanline pad, though end of
  147. // each character may be padded to next byte boundary
  148. // when needed. 16-bit offset means 64K max for bitmaps,
  149. // code currently doesn't check for overflow. (Doesn't
  150. // check that size & offsets are within bounds either for
  151. // that matter...please convert fonts responsibly.)
  152. table[j].bitmapOffset = bitmapOffset;
  153. table[j].width = bitmap->width;
  154. table[j].height = bitmap->rows;
  155. table[j].xAdvance = face->glyph->advance.x >> 6;
  156. table[j].xOffset = g->left;
  157. table[j].yOffset = 1 - g->top;
  158. for (y = 0; y < bitmap->rows; y++) {
  159. for (x = 0; x < bitmap->width; x++) {
  160. byte = x / 8;
  161. bit = 0x80 >> (x & 7);
  162. enbit(bitmap->buffer[y * bitmap->pitch + byte] & bit);
  163. }
  164. }
  165. // Pad end of char bitmap to next byte boundary if needed
  166. int n = (bitmap->width * bitmap->rows) & 7;
  167. if (n) { // Pixel count not an even multiple of 8?
  168. n = 8 - n; // # bits to next multiple
  169. while (n--)
  170. enbit(0);
  171. }
  172. bitmapOffset += (bitmap->width * bitmap->rows + 7) / 8;
  173. FT_Done_Glyph(glyph);
  174. }
  175. printf(" };\n\n"); // End bitmap array
  176. // Output glyph attributes table (one per character)
  177. printf("const GFXglyph %sGlyphs[] PROGMEM = {\n", fontName);
  178. for (i = first, j = 0; i <= last; i++, j++) {
  179. printf(" { %5d, %3d, %3d, %3d, %4d, %4d }", table[j].bitmapOffset,
  180. table[j].width, table[j].height, table[j].xAdvance, table[j].xOffset,
  181. table[j].yOffset);
  182. if (i < last) {
  183. printf(", // 0x%02X", i);
  184. if ((i >= ' ') && (i <= '~')) {
  185. printf(" '%c'", i);
  186. }
  187. putchar('\n');
  188. }
  189. }
  190. printf(" }; // 0x%02X", last);
  191. if ((last >= ' ') && (last <= '~'))
  192. printf(" '%c'", last);
  193. printf("\n\n");
  194. // Output font structure
  195. printf("const GFXfont %s PROGMEM = {\n", fontName);
  196. printf(" (uint8_t *)%sBitmaps,\n", fontName);
  197. printf(" (GFXglyph *)%sGlyphs,\n", fontName);
  198. if (face->size->metrics.height == 0) {
  199. // No face height info, assume fixed width and get from a glyph.
  200. printf(" 0x%02X, 0x%02X, %d };\n\n", first, last, table[0].height);
  201. } else {
  202. printf(" 0x%02X, 0x%02X, %ld };\n\n", first, last,
  203. face->size->metrics.height >> 6);
  204. }
  205. printf("// Approx. %d bytes\n", bitmapOffset + (last - first + 1) * 7 + 7);
  206. // Size estimate is based on AVR struct and pointer sizes;
  207. // actual size may vary.
  208. FT_Done_FreeType(library);
  209. return 0;
  210. }
  211. /* -------------------------------------------------------------------------
  212. Character metrics are slightly different from classic GFX & ftGFX.
  213. In classic GFX: cursor position is the upper-left pixel of each 5x7
  214. character; lower extent of most glyphs (except those w/descenders)
  215. is +6 pixels in Y direction.
  216. W/new GFX fonts: cursor position is on baseline, where baseline is
  217. 'inclusive' (containing the bottom-most row of pixels in most symbols,
  218. except those with descenders; ftGFX is one pixel lower).
  219. Cursor Y will be moved automatically when switching between classic
  220. and new fonts. If you switch fonts, any print() calls will continue
  221. along the same baseline.
  222. ...........#####.. -- yOffset
  223. ..........######..
  224. ..........######..
  225. .........#######..
  226. ........#########.
  227. * = Cursor pos. ........#########.
  228. .......##########.
  229. ......#####..####.
  230. ......#####..####.
  231. *.#.. .....#####...####.
  232. .#.#. ....##############
  233. #...# ...###############
  234. #...# ...###############
  235. ##### ..#####......#####
  236. #...# .#####.......#####
  237. ====== #...# ====== #*###.........#### ======= Baseline
  238. || xOffset
  239. glyph->xOffset and yOffset are pixel offsets, in GFX coordinate space
  240. (+Y is down), from the cursor position to the top-left pixel of the
  241. glyph bitmap. i.e. yOffset is typically negative, xOffset is typically
  242. zero but a few glyphs will have other values (even negative xOffsets
  243. sometimes, totally normal). glyph->xAdvance is the distance to move
  244. the cursor on the X axis after drawing the corresponding symbol.
  245. There's also some changes with regard to 'background' color and new GFX
  246. fonts (classic fonts unchanged). See Adafruit_GFX.cpp for explanation.
  247. */
  248. #endif /* !ARDUINO */