Banner/mkfont.c

382 lines
10 KiB
C
Raw Normal View History

2023-12-08 17:20:48 +01:00
#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);
}