MBED Import of ADAFRUIT graphics library, BSD License

Dependents:   GP9002adafruit GP9002af_gray

Notes on this library

This was imported into MBED specifically to support the GP9002 VFD, as a result it has some "hacks" to optimize it for the GP9002.

Due to the GP9002 internal organization it draws vertical lines much faster than horizontal (assuming you orient it "landscape"). This is likely to be true of other displays that have bits in a byte arranged vertically, which seems a common theme in small GLCDs. Some types may have a more CGA-like memory organization and will draw faster horizontally.

On a vertical-organised display the graphics functions are often substantially faster if X and Y are exchanged, especially with the dot-write optimization. This is because vertical lines can be written byte-at-a-time with no need for read-modify-write, and even when individual bits are written a significant number will "land" in the byte previously written. In contrast a horizontal line would require changing one bit of each byte in turn, requiring a sequence of set-address,read,write operations for each dot in turn.

I've hacked this in the library. I forget exactly how but I believe I simply exchanged X with W in the code for drawing filled shapes.

I would like to come up with a more generic way to do this, such as having internal coordinates that are not defined as X and Y, then leaving it up to the display library to "wrap" them in the way that is best for that display.

I would like to apologize for abandoning this project, but the test harness still exists and I might return to it, though I'm more interested in TFT systems like the STM discovery now.

Committer:
oliverb
Date:
Sat May 07 12:50:37 2016 +0000
Revision:
0:3bf8ef959338
Converting to Library, this is a base class that needs extending for a specific device. Note that as it stands it favors devices with vertical bit-organisation

Who changed what in which revision?

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