#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <ft2build.h> #include FT_FREETYPE_H #include FT_GLYPH_H #include FT_TRUETYPE_DRIVER_H #include FT_MODULE_H #include <getopt.h> #define OPCODE_REPEAT 253 #define OPCODE_EOL 254 #define OPCODE_EOC 255 #define MAX_RLE 80 /* Maximum number of repeats */ /**************************************************************************** * BYTEPOINTER FUNCTIONS ****************************************************************************/ struct histogram { int position; int count; }; struct bytepointer { unsigned char *p; unsigned char *start; unsigned char *end; struct histogram histogram[256]; }; struct bitoutput { FILE *fp; int col; int byte_count; uint8_t byte; uint8_t bit; }; void init_bytepointer (struct bytepointer *bp, unsigned char *buffer, int n) { int i; bp->p = buffer; bp->start = buffer; bp->end = buffer + n; for (i=0; i<256; i++) { bp->histogram[i].position = i; bp->histogram[i].count = 0; } } void save_byte (struct bytepointer *bp, unsigned char byte) { if (bp->p == bp->end) { printf ("OUT OF BITPOINTER MEMORY.\n"); exit (2); } // If byte is more than MAX_RLE, break into MAX_RLE, 0, remainder while (byte < OPCODE_REPEAT && byte > MAX_RLE) { * (bp->p++) = MAX_RLE; * (bp->p++) = 0; byte -= MAX_RLE; } * (bp->p++) = byte; bp->histogram[byte].count++; } int histcmp (const void *p, const void *q) { struct histogram *p0 = (struct histogram *) p; struct histogram *q0 = (struct histogram *) q; return q0->count - p0->count; } void save_bits (struct bitoutput *bits, int bit) { if (bit) bits->byte |= bits->bit; bits->bit >>= 1; if (!bits->bit) { if (bits->col == 12) { fprintf (bits->fp, ",\n\t"); bits->col = 0; } else if (bits->col != 0) fprintf (bits->fp, ", "); fprintf (bits->fp, "0x%02X", bits->byte); bits->col++; bits->byte_count++; bits->bit = 0x80; bits->byte = 0; } } void output_bitstream (struct bytepointer *bp, int max_width, int scaled) { unsigned char *p; struct bitoutput bits; int col, i, v, lookup[256], offset, offsets[96]; qsort (bp->histogram, 256, sizeof (struct histogram), histcmp); for (i=0; i<256; i++) { lookup[bp->histogram[i].position] = i; } bits.fp = fopen ("font.h", "w"); bits.byte = 0; bits.bit = 0x80; bits.col = 0; bits.byte_count = 0; offset = 0; offsets[0] = 0; fprintf (bits.fp, "/********************************************************************\n" "* Font File format:\n" "* 2 bits: =0, opcode lut index 0\n" "* =1, opcode lut index is in next 3 bits + 1\n" "* =2, opcode lut index is in next 4 bits + 9\n" "* =3, opcode lut index is in next 6 bits + 25\n" "********************************************************************/\n"); fprintf (bits.fp, "unsigned char mfont[] = {\n\t"); for (p = bp->start; p <= bp->p; p++) { v = lookup[*p]; if (v == 0) { save_bits (&bits, 0); save_bits (&bits, 0); } else if (v < 9) { v = v-1; save_bits (&bits, 0); save_bits (&bits, 1); save_bits (&bits, v & 4); save_bits (&bits, v & 2); save_bits (&bits, v & 1); } else if (v < 25) { v = v-9; save_bits (&bits, 1); save_bits (&bits, 0); save_bits (&bits, v & 8); save_bits (&bits, v & 4); save_bits (&bits, v & 2); save_bits (&bits, v & 1); } else { v = v-25; save_bits (&bits, 1); save_bits (&bits, 1); save_bits (&bits, v & 32); save_bits (&bits, v & 16); save_bits (&bits, v & 8); save_bits (&bits, v & 4); save_bits (&bits, v & 2); save_bits (&bits, v & 1); } if (*p == OPCODE_EOC) { while (bits.bit != 0x80) save_bits (&bits, 0); offsets[++offset] = bits.byte_count; } } fprintf (bits.fp, "};\n"); fprintf (bits.fp, "unsigned char flut[] = {\n\t"); for (i=0, col=0; bp->histogram[i].count; i++) { if (col == 14) { fprintf (bits.fp, ",\n\t"); col = 0; } else if (col != 0) fprintf (bits.fp, ", "); fprintf (bits.fp, "%3d", bp->histogram[i].position); col++; bits.byte_count++; } fprintf (bits.fp, "};\n"); fprintf (bits.fp, "unsigned int foffs[] = {\n\t"); for (i=0, col=0; i<offset; i++) { if (col == 10) { fprintf (bits.fp, ",\n\t"); col = 0; } else if (col != 0) fprintf (bits.fp, ", "); fprintf (bits.fp, "%5d", offsets[i]); bits.byte_count += 2; col++; } fprintf (bits.fp, "};\n\n"); if (scaled) max_width += max_width; fprintf (bits.fp, "#define FONT_MAXWIDTH %d\n", max_width); fprintf (bits.fp, "#define FONT_DOUBLED %d\n\n", scaled); fprintf (bits.fp, "#define OPCODE_REPEAT %d\n", OPCODE_REPEAT); fprintf (bits.fp, "#define OPCODE_EOL %d\n", OPCODE_EOL); fprintf (bits.fp, "#define OPCODE_EOC %d\n", OPCODE_EOC); printf ("%d bytes.\n", bits.byte_count); } int main (int argc, char *argv[]) { int error; FT_Library library; FT_Face face; FT_GlyphSlot slot; FT_Glyph glyph; FT_Bitmap *bitmap; int advance, byte, c, x, y, y0, v, offset; uint8_t bit; int max_decender = 0; int max_width = 0; struct bytepointer bp; unsigned char buffer[48*1024]; int color, scaled, verbose; char *font = NULL; int ch, width, height; struct option longopts[] = { { "font", required_argument, NULL, 'f' }, { "width", required_argument, NULL, 'w' }, { "double", no_argument, &scaled, 1 }, { "verbose", no_argument, &verbose, 1 }, { NULL, 0, NULL, 0} }; width = 80; while ( (ch = getopt_long (argc, argv, "f:h:", longopts, NULL)) != -1) { switch (ch) { case 'f': font = optarg; break; case 'w': width = atoi (optarg); break; case 0: break; default: fprintf (stderr, "mkfont: --font FONTNAME [--width HEIGHT]\n"); exit (2); } } if (!font) { fprintf (stderr, "No font specified. Use --font option\n"); exit (2); } /* Adjust width to account for 0 base */ if (scaled) width /= 2; width--; height = width * 6 / 10; init_bytepointer (&bp, buffer, sizeof (buffer)); if ( (error = FT_Init_FreeType (&library))) { fprintf (stderr, "Error initializing FreeType"); exit (2); } FT_UInt version = TT_INTERPRETER_VERSION_35; FT_Property_Set (library, "truetype", "interpreter-version", &version); if ( (error = FT_New_Face (library, font, 0, &face))) { fprintf (stderr, "Error loading Face"); exit (2); } // Height, width reversed below because characters are rotated if ( (error = FT_Set_Pixel_Sizes (face, height, width))) { fprintf (stderr, "Error setting pixel size"); exit (2); } /* Find maximum decender and width */ for (c=32; c < 127; c++) { if ( (error = FT_Load_Char (face, c, FT_LOAD_TARGET_MONO))) { fprintf (stderr, "Error loading char"); exit (2); } slot = face->glyph; if ( (error = FT_Render_Glyph (slot, FT_RENDER_MODE_MONO))) { fprintf (stderr, "Error loading char"); exit (2); } if ( (error = FT_Get_Glyph (slot, &glyph))) { fprintf (stderr, "Error loading char"); exit (2); } bitmap = &slot->bitmap; if ( (int) (slot->bitmap_top - bitmap->rows) < max_decender) { max_decender = slot->bitmap_top - bitmap->rows; } if (bitmap->rows > max_width) max_width = bitmap->rows; } max_width++; /* Generate glyphs and encode */ for (c=32; c < 127; c++) { if ( (error = FT_Load_Char (face, c, FT_LOAD_TARGET_MONO))) { fprintf (stderr, "Error loading char"); exit (2); } slot = face->glyph; if ( (error = FT_Render_Glyph (slot, FT_RENDER_MODE_MONO))) { fprintf (stderr, "Error loading char"); exit (2); } if ( (error = FT_Get_Glyph (slot, &glyph))) { fprintf (stderr, "Error loading char"); exit (2); } bitmap = &slot->bitmap; advance = slot->bitmap_left; if (advance < 0) advance = 0; color = 0; for (; advance > 0; advance--) { save_byte (&bp, OPCODE_EOL); if (verbose) printf ("\n"); } for (x=0; x < bitmap->width; x++) { int repeat = 0; // Check for repeating line if (x > 0) { int v0; for (y = bitmap->rows-1; y >= 0; y--) { byte = (x-1) /8; bit = 0x80 >> ( (x-1) &7); v0 = (bitmap->buffer[y*bitmap->pitch + byte]&bit) ? 1: 0; byte = x/8; bit = 0x80 >> (x&7); v = (bitmap->buffer[y*bitmap->pitch + byte]&bit) ? 1: 0; if (v0 != v) break; } if (y < 0) repeat = 1; } // Find end of spaces for (y0=0; y0<bitmap->rows; y0++) { byte = x/8; bit = 0x80 >> (x&7); v = (bitmap->buffer[y0*bitmap->pitch + byte]&bit) ? 1: 0; if (v) break; } offset = -max_decender+ (slot->bitmap_top - bitmap->rows); if (y0 == bitmap->rows) offset = 0; if (verbose) { for (y=0; y<offset; y++) { printf (" "); } } for (y=bitmap->rows-1; y>=y0; y--) { byte = x/8; bit = 0x80 >> (x&7); v = (bitmap->buffer[y*bitmap->pitch + byte]&bit) ? 1: 0; if (verbose) { if (v) printf (repeat ? "*" : "#"); else printf (" "); } if (v==color) offset++; else { if (!repeat) save_byte (&bp, offset); color ^= 1; offset = 1; } } if (repeat) { save_byte (&bp, OPCODE_REPEAT); } else { save_byte (&bp, offset); save_byte (&bp, OPCODE_EOL); } color = 0; if (verbose) printf ("\n"); } advance = (slot->advance.x >> 6) - bitmap->width - ( (slot->bitmap_left > 0) ? slot->bitmap_left : 0); if (advance < 0) advance = 0; for (; advance > 0; advance--) { save_byte (&bp, OPCODE_EOL); if (verbose) printf ("\n"); } save_byte (&bp, OPCODE_EOC); FT_Done_Glyph (glyph); } output_bitstream (&bp, max_width, scaled); }