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