You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

509 lines
13 KiB

/** @file fontgen.c
@author M. P. Hayes, UCECE
@date 15 May 2007
@brief
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdint.h>
#include <ctype.h>
#include <time.h>
/* FIXME. This is not robust. It's an ugly hack. Rewrite in python! */
typedef struct
{
char name[64];
char *comment;
uint8_t width;
uint8_t height;
uint8_t offset;
uint8_t size;
uint8_t bytes;
uint8_t interlaced;
uint8_t *data;
} font_t;
#define FONT_SIZE_MAX 255
int font_zoom (font_t *font, font_t *zoom_font, int zoom_x, int zoom_y)
{
int i;
uint8_t *image;
uint8_t *zoom_image;
int bits;
*zoom_font = *font;
zoom_font->width = font->width * zoom_x;
zoom_font->height = font->height * zoom_y;
zoom_font->bytes = font->bytes * zoom_x * zoom_y;
zoom_font->data = calloc (FONT_SIZE_MAX, zoom_font->bytes);
bits = zoom_font->width * zoom_font->height;
if (zoom_font->interlaced)
bits = (bits + 1) / 2;
zoom_font->bytes = (bits + CHAR_BIT - 1) / CHAR_BIT;
image = malloc (font->width * font->height);
zoom_image = malloc (font->width * zoom_x * font->height * zoom_y);
for (i = font->offset; i < font->size + font->offset; i++)
{
int k;
int x;
int y;
uint8_t font_byte;
uint8_t *font_elt;
font_elt = &font->data[i * font->bytes];
k = 0;
font_byte = *font_elt++;
for (y = 0; y < font->height; y++)
{
for (x = 0; x < font->width; x++)
{
image[y * font->width + x] = (font_byte & 1) * 255;
font_byte >>= 1;
k++;
if (k >= CHAR_BIT)
{
k = 0;
font_byte = *font_elt++;
}
}
}
for (y = 0; y < zoom_font->height; y++)
{
for (x = 0; x < zoom_font->width; x++)
zoom_image[y * zoom_font->width + x]
= image[(y / zoom_y) * font->width + (x / zoom_x)];
}
font_elt = &zoom_font->data[i * zoom_font->bytes];
k = 0;
*font_elt = 0;
for (y = 0; y < zoom_font->height; y++)
{
for (x = 0; x < zoom_font->width; x++)
{
if (zoom_image[y * zoom_font->width + x])
*font_elt |= (1 << k);
k++;
if (k >= CHAR_BIT)
{
k = 0;
font_elt++;
*font_elt = 0;
}
}
}
}
free (image);
free (zoom_image);
return 1;
}
int font_scan (font_t *font)
{
char buffer[132];
int line;
int symcnt;
int symline;
uint8_t symbol;
uint8_t symbol_min;
uint8_t symbol_max;
int tmp;
int bits;
unsigned int i;
font->comment = 0;
font->interlaced = 0;
/* FIXME, use more robust key-value pair parsing. */
while (1)
{
int c;
c = fgetc (stdin);
if (c == EOF)
return 0;
ungetc (c, stdin);
/* Ignore lines starting with #, w, h, i. */
if (!strchr ("#whi", c))
break;
if (!fgets (buffer, sizeof (buffer), stdin))
return 0;
if (c == 'w')
{
if (sscanf (buffer, "width=%d", &tmp) != 1)
fprintf (stderr, "Width parse error: %s\n", buffer);
font->width = tmp;
}
else if (c == 'h')
{
if (sscanf (buffer, "height=%d", &tmp) != 1)
fprintf (stderr, "Height parse error: %s\n", buffer);
font->height = tmp;
}
else if (c == 'i')
{
if (sscanf (buffer, "interlaced=%d", &tmp) != 1)
fprintf (stderr, "Interlaced parse error: %s\n", buffer);
font->interlaced = tmp;
}
else if (c == '#')
{
if (!font->comment)
font->comment = calloc (1, strlen (buffer) + 1);
else
font->comment = realloc (font->comment,
strlen (font->comment)
+ strlen (buffer) + 1);
strcat (font->comment, buffer + 1);
}
}
if (!font->width)
{
fprintf (stderr, "Missing width specifier\n");
return 1;
}
if (!font->height)
{
fprintf (stderr, "Missing height specifier\n");
return 1;
}
bits = font->width * font->height;
if (font->interlaced)
bits = (bits + 1) / 2;
font->bytes = (bits + CHAR_BIT - 1) / CHAR_BIT;
font->offset = 0;
font->size = ~0;
symbol_min = ~0;
symbol_max = 0;
font->data = calloc (FONT_SIZE_MAX, font->bytes);
symbol = 0;
line = 4;
for (symcnt = 1; ; symcnt++)
{
int bit = 0;
for (symline = 1; symline <= font->height + 1; symline++)
{
unsigned int num;
if (!fgets (buffer, sizeof (buffer), stdin))
{
/* Have reached end of file. */
font->offset = symbol_min;
font->size = symbol_max - symbol_min + 1;
return 0;
}
/* Remove newline. */
buffer[strlen (buffer) - 1] = '\0';
if (symline != 1)
{
char *p;
if (strlen (buffer) != font->width)
{
fprintf (stderr, "Parse error at line %d: %s\n", line, buffer);
return 1;
}
p = buffer;
if (font->interlaced)
{
num = symline & 1 ? font->width / 2 : (font->width + 1) / 2;
if (symline & 1)
p++;
}
else
num = font->width;
for (i = 0; i < num; i++)
{
if (*p != '.')
{
font->data[symbol * font->bytes + bit / CHAR_BIT]
|= (1 << (bit % CHAR_BIT));
}
else if (*p != '.')
{
fprintf (stderr, "Parse error at line %d: %c\n", line, *p);
return 1;
}
bit++;
if (font->interlaced)
p += 2;
else
p++;
}
}
else
{
if (buffer[0] == '\\' && buffer[1] != '\0')
{
if (sscanf (buffer + 1, "%o", &tmp) != 1)
{
fprintf (stderr, "Parse error (octal num) at line %d: %s\n", line, buffer);
return 2;
}
symbol = tmp;
}
else
{
char sym;
if (sscanf (buffer, "%c", &sym) != 1)
{
fprintf (stderr, "Parse error (char) at line %d: %s\n", line, buffer);
return 2;
}
symbol = sym;
}
if (symbol < symbol_min)
symbol_min = symbol;
if (symbol > symbol_max)
symbol_max = symbol;
}
line++;
}
}
}
static void font_print_1 (font_t *font, uint8_t symbol)
{
int i;
for (i = 0; i < font->bytes; i++)
printf ("0x%02x, ", font->data[symbol * font->bytes + i]);
fputs ("\n", stdout);
}
static void font_rotate (font_t *font, font_t *rotate_font)
{
int i;
int x;
int y;
*rotate_font = *font;
rotate_font->width = font->height;
rotate_font->height = font->width;
rotate_font->data = calloc (FONT_SIZE_MAX, font->bytes);
for (i = 0; i < font->size; i++)
{
for (y = 0; y < font->height; y++)
{
for (x = 0; x < font->width; x++)
{
int bit;
int newbit;
bit = y * font->width + x;
newbit = x * font->height + y;
if (font->data[i * font->bytes + bit / CHAR_BIT]
& (1 << (bit % CHAR_BIT)))
rotate_font->data[i * font->bytes + newbit / CHAR_BIT]
|= (1 << (newbit % CHAR_BIT));
}
}
}
}
static void font_print (font_t *font)
{
int i;
uint8_t bytes_per_char;
time_t now;
char name_upper[128];
char timestr[32];
bytes_per_char = (font->width * font->height + CHAR_BIT - 1) / CHAR_BIT;
for (i= 0; font->name[i]; i++)
name_upper[i] = toupper (font->name[i]);
name_upper[i] = '\0';
time (&now);
strftime (timestr, sizeof (timestr), "%d %b %Y", localtime (&now));
printf ("/** @file %s.h\n", font->name);
printf (" @author fontgen\n");
printf (" @date %s\n\n", timestr);
printf (" @defgroup %s %s\n", font->name, font->comment);
printf ("*/\n\n");
printf ("#ifndef %s_H_\n", name_upper);
printf ("#define %s_H_\n\n", name_upper);
printf ("#define %s_WIDTH %d\n", name_upper, font->width);
printf ("#define %s_HEIGHT %d\n", name_upper, font->height);
printf ("#define %s_OFFSET %d\n", name_upper, font->offset);
printf ("#define %s_SIZE %d\n\n", name_upper, font->size);
printf ("#ifndef FONT_WIDTH\n#define FONT_WIDTH %d\n#endif\n",
font->width);
printf ("#ifndef FONT_HEIGHT\n#define FONT_HEIGHT %d\n#endif\n",
font->height);
printf ("#ifndef FONT_OFFSET\n#define FONT_OFFSET %d\n#endif\n",
font->offset);
printf ("#ifndef FONT_SIZE_MAX\n#define FONT_SIZE_MAX %d\n#endif\n",
font->size);
printf ("#include \"font.h\"\n\n");
printf ("static font_t %s =\n{\n", font->name);
printf (" .flags = 1, /* (packed) */\n");
printf (" .width = %d,\n", font->width);
printf (" .height = %d,\n", font->height);
printf (" .offset = %d,\n", font->offset);
printf (" .size = %d,\n", font->size);
printf (" .bytes = %d,\n", bytes_per_char);
printf (" .data =\n {\n");
for (i = font->offset; i < font->size + font->offset; i++)
{
if (i < 32)
printf (" /* \\%o */\n ", i);
else
printf (" /* %c */\n ", i);
font_print_1 (font, i);
}
printf (" }\n};\n#endif /* %s_H_ */\n", name_upper);
}
static void font_draw_1 (font_t *font, uint8_t symbol)
{
int i;
int j;
int bit;
char ch;
uint8_t *data;
data = &font->data[symbol * font->bytes];
bit = 0;
ch = *data++;
for (i = 0; i < font->height; i++)
{
for (j = 0; j < font->width; j++)
{
if (font->interlaced && ((i & 1) ^ (j & 1)))
{
fputc (' ', stdout);
continue;
}
fputc (ch & 1 ? '@' : '.', stdout);
ch >>= 1;
bit++;
if ((bit % CHAR_BIT) == 0)
ch = *data++;
}
fputc ('\n', stdout);
}
}
static void font_draw (font_t *font)
{
int i;
printf ("width=%d\n", font->width);
printf ("height=%d\n", font->height);
printf ("interlaced=%d\n", font->interlaced);
for (i = 0; i < 32; i++)
{
printf ("\\%o\n", i);
font_draw_1 (font, i);
}
for (; i < FONT_SIZE_MAX; i++)
{
printf ("%c\n", i);
font_draw_1 (font, i);
}
}
int main (int argc, char **argv)
{
int ret;
font_t font;
ret = font_scan (&font);
if (ret)
return ret;
if (argc < 2)
{
fprintf (stderr, "Usage: fontgen fontname\n");
return 1;
}
strcpy (font.name, argv[1]);
argc--;
argv++;
if (argc > 2 && !strcmp (argv[1], "--zoom"))
{
int zoom;
font_t zoom_font;
zoom = atoi (argv[2]);
argc -= 2;
argv += 2;
font_zoom (&font, &zoom_font, zoom, zoom);
font = zoom_font;
}
if (argc > 1 && !strcmp (argv[1], "--rotate"))
{
font_t rotate_font;
argc -= 1;
argv += 1;
font_rotate (&font, &rotate_font);
font = rotate_font;
}
if (argc > 1 && !strcmp (argv[1], "--ascii"))
font_draw (&font);
else
font_print (&font);
return 0;
}