arduinoprojects

git clone https://git.tarina.org/arduinoprojects
Log | Files | Refs

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 */