Convert BDF bitmap fonts to flf fonts for figlet
git clone https://github.com/m-col/bdf2flf
Files | Refs | Readme

-rw-r--r-- bdf2flf.c


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 #define PROGNAME "bdf2flf"
      6 
      7 
      8 // These are the characters required at the start of FIGfonts.
      9 const unsigned int REQUIRED[] = {
     10     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
     11     51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
     12     70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
     13     89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105,
     14     106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
     15     121, 122, 123, 124, 125, 126, 196, 214, 220, 228, 246, 252, 223
     16 };
     17 
     18 
     19 struct character {
     20     unsigned int width;
     21     unsigned int encoding;
     22     char *bitmap;
     23     _Bool printed;
     24 };
     25 
     26 
     27 void die(char *msg)
     28 {
     29     fprintf(stderr, msg);
     30     exit(EXIT_FAILURE);
     31 }
     32 
     33 
     34 void put_pixel(unsigned int c, unsigned int bit, FILE *out)
     35 {
     36 
     37     if (c & bit) {
     38 	fputc('#', out);
     39     } else {
     40 	fputc(' ', out);
     41     }
     42 }
     43 
     44 
     45 void print_character(FILE *out, char *bitmap, unsigned int width, unsigned int height)
     46 {
     47     unsigned int y;
     48     unsigned int x;
     49     int c;
     50     unsigned int bit;
     51     size_t hex_chars = (width + 7) / 8 * 2;
     52     char *s;
     53     s = malloc(hex_chars);
     54 
     55     for (y = 0; y < height; y++) {
     56 	memset(s, 0, strlen(s));
     57 	if (y)
     58 	    fprintf(out, "\n");
     59 	for (x = 0; x < hex_chars; x++) {
     60 	    strncat(s, bitmap, 1);
     61 	    bitmap++;
     62 	}
     63 
     64 	c = (int)strtol(s, NULL, 16);
     65 	bit = 0x80 * hex_chars / 2;
     66 	for (x = 0; x < width; x++) {
     67 	    put_pixel(c, bit, out);
     68 	    if (bit == 1)
     69 		break;
     70 	    bit = bit / 2;
     71 	}
     72 	fprintf(out, "$@");
     73     }
     74 
     75     fprintf(out, "@\n");
     76     free(s);
     77 }
     78 
     79 
     80 void bdf2flf(FILE * in, FILE * out)
     81 {
     82     char *s;
     83     char linebuf[1024];
     84     char font[1024];
     85     char copyright[1024];
     86     int baseline, codetags, i;
     87     int comments = 3;
     88     int num_chars = 0;
     89     int width = 0;
     90     int height = 0;
     91     char bitmap[4 * 32];
     92     int n = 0;
     93     struct character *chars;
     94     const unsigned int *j;
     95 
     96     // Some of the bdf-reading logic is derived from bdf2c (c) Lutz Sammer.
     97     // extract bdf headers
     98     for (;;) {
     99 	if (!fgets(linebuf, sizeof(linebuf), in)) {	// EOF
    100 	    break;
    101 	}
    102 	if (!(s = strtok(linebuf, " \t\n\r"))) {	// empty line
    103 	    break;
    104 	}
    105 	if (!strcasecmp(s, "FONTBOUNDINGBOX")) {
    106 	    width = atoi(strtok(NULL, " \t\n\r"));
    107 	    height = atoi(strtok(NULL, " \t\n\r"));
    108 	    strtok(NULL, " \t\n\r");
    109 	    baseline = height + atoi(strtok(NULL, " \t\n\r"));
    110 
    111 	} else if (!strcasecmp(s, "FONT")) {
    112 	    strcpy(font, strtok(NULL, "\n"));
    113 
    114 	} else if (!strcasecmp(s, "COPYRIGHT")) {
    115 	    strcpy(copyright, strtok(NULL, "\n"));
    116 	    comments = 4;
    117 
    118 	} else if (!strcasecmp(s, "CHARS")) {
    119 	    num_chars = atoi(strtok(NULL, " \t\n\r"));
    120 	    break;
    121 	}
    122     }
    123 
    124     if (num_chars <= 0 || width <= 0 || height <= 0)
    125 	die("Could not extract BDF data. Is the input a BDF file?\n");
    126 
    127     if (width > 32 || height > 32)
    128 	die("bdf fonts this large are not supported, sorry.\n");
    129 
    130     chars = malloc(num_chars * sizeof(struct character));
    131     if (!chars)
    132 	die("Could not allocate memory.\n");
    133 
    134     // extract individual char data
    135     for (;;) {
    136 	if (!fgets(linebuf, sizeof(linebuf), in))
    137 	    break;
    138 	if (!(s = strtok(linebuf, " \t\n\r")))
    139 	    continue;
    140 	if (!strcasecmp(s, "ENCODING")) {
    141 	    chars[n].encoding = atoi(strtok(NULL, " \t\n\r"));
    142 	} else if (!strcasecmp(s, "BBX")) {
    143 	    chars[n].width = atoi(strtok(NULL, " \t\n\r"));
    144 	} else if (!strcasecmp(s, "BITMAP")) {
    145 	    if (n == num_chars)
    146 		die("bdf font has incorrect CHARS value.\n");
    147 	    i = 0;
    148 	    chars[n].printed = 0;
    149 	    chars[n].bitmap = malloc((width + 7) / 8 * height * 2);
    150 	    chars[n].bitmap[0] = '\0';
    151 	    for (;;) {
    152 		fgets(linebuf, sizeof(linebuf), in);
    153 		s = strtok(linebuf, "\n\r");
    154 		if (!strcasecmp(s, "ENDCHAR")) {
    155 		    break;
    156 		}
    157 		strncat(chars[n].bitmap, s, 4);
    158 		i++;
    159 	    }
    160 	    n++;
    161 	}
    162     }
    163 
    164     // output flf header
    165     codetags = 0;
    166     fprintf(out, "flf2a$ %i %i %i -1 %i 0 16384 %i\n", height, baseline, width+2,
    167 	    comments, codetags);
    168     fprintf(out, "FIGlet font derived from %s\n", font);
    169     if (comments > 3)
    170 	fprintf(out, "which has copyright: %s\n", copyright);
    171     fprintf(out, "Converted to flf with bdf2flf (c) 2020 Matt Colligan.\n\n");
    172 
    173     // print required characters first
    174     n = 0;
    175     j = &REQUIRED[0];
    176     i = 0;
    177     for (;;) {
    178 	if (chars[n].encoding == *j) {
    179 	    strncpy(bitmap, chars[n].bitmap, ((width + 7) / 8) * height * 2);
    180 	    print_character(out, bitmap, chars[n].width, height);
    181 	    chars[n].printed = 1;
    182 	    if (*j == 223)
    183 		break;
    184 	    j++;
    185 	    i = 0;
    186 	}
    187 	n++;
    188 	i++;
    189 	if (n == num_chars)
    190 	    n = 0;
    191 	if (i == num_chars)
    192 	    break;
    193     }
    194 
    195     // print additional characters second
    196     for (n = 0; n < num_chars; n++) {
    197 	if (!chars[n].printed) {
    198 	    strncpy(bitmap, chars[n].bitmap, ((width + 7) / 8) * height * 2);
    199 	    print_character(out, bitmap, chars[n].width, height);
    200 	}
    201 	free(chars[n].bitmap);
    202     }
    203 }
    204 
    205 
    206 int main(int argc, char *argv[])
    207 {
    208     if (argc > 1) {
    209 	printf(PROGNAME " < input.bdf > output.flf\nbdf data is read from stdin"
    210 		" and figlet font data is output to stdout.\n");
    211 	exit(EXIT_SUCCESS);
    212     }
    213 
    214     bdf2flf(stdin, stdout);
    215 
    216     (void)(argv);  // shush the compiler
    217     return 0;
    218 }
    219