-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