151static struct glyph * 152add_glyph(const uint8_t *bytes, unsigned int map_idx, int fallback) 153{ 154 struct glyph *gl; 155 int hash; 156 157 glyph_total++; 158 glyph_count[map_idx]++; 159 160 hash = fnv_32_buf(bytes, wbytes * height, FNV1_32_INIT) % FONTCVT_NHASH; 161 SLIST_FOREACH(gl, &glyph_hash[hash], g_hash) { 162 if (memcmp(gl->g_data, bytes, wbytes * height) == 0) { 163 glyph_dupe++; 164 return (gl); 165 } 166 } 167 168 gl = malloc(sizeof *gl); 169 gl->g_data = malloc(wbytes * height); 170 memcpy(gl->g_data, bytes, wbytes * height); 171 if (fallback) 172 TAILQ_INSERT_HEAD(&glyphs[map_idx], gl, g_list); 173 else 174 TAILQ_INSERT_TAIL(&glyphs[map_idx], gl, g_list); 175 SLIST_INSERT_HEAD(&glyph_hash[hash], gl, g_hash); 176 177 glyph_unique++; 178 return (gl); 179} 180 181static int 182add_char(unsigned curchar, unsigned map_idx, uint8_t *bytes, uint8_t *bytes_r) 183{ 184 struct glyph *gl; 185 186 /* Prevent adding two glyphs for 0xFFFD */ 187 if (curchar == 0xFFFD) { 188 if (map_idx < VFNT_MAP_BOLD) 189 gl = add_glyph(bytes, 0, 1); 190 } else if (curchar >= 0x20) { 191 gl = add_glyph(bytes, map_idx, 0); 192 if (add_mapping(gl, curchar, map_idx) != 0) 193 return (1); 194 if (bytes_r != NULL) { 195 gl = add_glyph(bytes_r, map_idx + 1, 0); 196 if (add_mapping(gl, curchar, 197 map_idx + 1) != 0) 198 return (1); 199 } 200 } 201 return (0); 202} 203 204 205static int 206parse_bitmap_line(uint8_t *left, uint8_t *right, unsigned int line, 207 unsigned int dwidth) 208{ 209 uint8_t *p; 210 unsigned int i, subline; 211 212 if (dwidth != width && dwidth != width * 2) { 213 errx(1, 214 "Bitmap with unsupported width %u!\n", dwidth); 215 return (1); 216 } 217 218 /* Move pixel data right to simplify splitting double characters. */ 219 line >>= (howmany(dwidth, 8) * 8) - dwidth; 220 221 for (i = dwidth / width; i > 0; i--) { 222 p = (i == 2) ? right : left; 223 224 subline = line & ((1 << width) - 1); 225 subline <<= (howmany(width, 8) * 8) - width; 226 227 if (wbytes == 1) { 228 *p = subline; 229 } else if (wbytes == 2) { 230 *p++ = subline >> 8; 231 *p = subline; 232 } else { 233 errx(1, 234 "Unsupported wbytes %u!\n", wbytes); 235 return (1); 236 } 237 238 line >>= width; 239 } 240 241 return (0); 242} 243 244static int 245parse_bdf(FILE *fp, unsigned int map_idx) 246{ 247 char *ln; 248 size_t length; 249 uint8_t bytes[wbytes * height], bytes_r[wbytes * height]; 250 unsigned int curchar = 0, dwidth = 0, i, line; 251 252 while ((ln = fgetln(fp, &length)) != NULL) { 253 ln[length - 1] = '\0'; 254 255 if (strncmp(ln, "ENCODING ", 9) == 0) { 256 curchar = atoi(ln + 9); 257 } 258 259 if (strncmp(ln, "DWIDTH ", 7) == 0) { 260 dwidth = atoi(ln + 7); 261 } 262 263 if (strncmp(ln, "BITMAP", 6) == 0 && 264 (ln[6] == ' ' || ln[6] == '\0')) { 265 for (i = 0; i < height; i++) { 266 if ((ln = fgetln(fp, &length)) == NULL) { 267 errx(1, "Unexpected EOF!\n"); 268 return (1); 269 } 270 ln[length - 1] = '\0'; 271 sscanf(ln, "%x", &line); 272 if (parse_bitmap_line(bytes + i * wbytes, 273 bytes_r + i * wbytes, line, dwidth) != 0) 274 return (1); 275 } 276 277 if (add_char(curchar, map_idx, bytes, 278 dwidth == width * 2 ? bytes_r : NULL) != 0) 279 return (1); 280 } 281 } 282 283 return (0); 284} 285 286static int 287parse_hex(FILE *fp, unsigned int map_idx) 288{ 289 char *ln, *p; 290 char fmt_str[8]; 291 size_t length; 292 uint8_t bytes[wbytes * height], bytes_r[wbytes * height]; 293 unsigned curchar = 0, i, line, chars_per_row, dwidth; 294 295 while ((ln = fgetln(fp, &length)) != NULL) { 296 ln[length - 1] = '\0'; 297 298 if (strncmp(ln, "# Height: ", 10) == 0) { 299 height = atoi(ln + 10); 300 } else if (strncmp(ln, "# Width: ", 9) == 0) { 301 width = atoi(ln + 9); 302 } else if (sscanf(ln, "%4x:", &curchar)) { 303 p = ln + 5; 304 chars_per_row = strlen(p) / height; 305 dwidth = width; 306 if (chars_per_row / 2 > width / 8) 307 dwidth *= 2; /* Double-width character. */ 308 snprintf(fmt_str, sizeof(fmt_str), "%%%ux", 309 chars_per_row); 310 311 for (i = 0; i < height; i++) { 312 sscanf(p, fmt_str, &line); 313 p += chars_per_row; 314 if (parse_bitmap_line(bytes + i * wbytes, 315 bytes_r + i * wbytes, line, dwidth) != 0) 316 return (1); 317 } 318 319 if (add_char(curchar, map_idx, bytes, 320 dwidth == width * 2 ? bytes_r : NULL) != 0) 321 return (1); 322 } 323 } 324 return (0); 325} 326 327static int 328parse_file(const char *filename, unsigned int map_idx) 329{ 330 FILE *fp; 331 size_t len; 332 333 fp = fopen(filename, "r"); 334 if (fp == NULL) { 335 perror(filename); 336 return (1); 337 } 338 len = strlen(filename); 339 if (len > 4 && strcasecmp(filename + len - 4, ".hex") == 0) 340 return parse_hex(fp, map_idx); 341 return parse_bdf(fp, map_idx); 342} 343 344static void 345number_glyphs(void) 346{ 347 struct glyph *gl; 348 unsigned int i, idx = 0; 349 350 for (i = 0; i < VFNT_MAPS; i++) 351 TAILQ_FOREACH(gl, &glyphs[i], g_list) 352 gl->g_index = idx++; 353} 354 355static void 356write_glyphs(FILE *fp) 357{ 358 struct glyph *gl; 359 unsigned int i; 360 361 for (i = 0; i < VFNT_MAPS; i++) { 362 TAILQ_FOREACH(gl, &glyphs[i], g_list) 363 fwrite(gl->g_data, wbytes * height, 1, fp); 364 } 365} 366 367static void 368fold_mappings(unsigned int map_idx) 369{ 370 struct mapping_list *ml = &maps[map_idx]; 371 struct mapping *mn, *mp, *mbase; 372 373 mp = mbase = TAILQ_FIRST(ml); 374 for (mp = mbase = TAILQ_FIRST(ml); mp != NULL; mp = mn) { 375 mn = TAILQ_NEXT(mp, m_list); 376 if (mn != NULL && mn->m_char == mp->m_char + 1 && 377 mn->m_glyph->g_index == mp->m_glyph->g_index + 1) 378 continue; 379 mbase->m_length = mp->m_char - mbase->m_char + 1; 380 mbase = mp = mn; 381 map_folded_count[map_idx]++; 382 } 383} 384 385struct file_mapping { 386 uint32_t source; 387 uint16_t destination; 388 uint16_t length; 389} __packed; 390 391static void 392write_mappings(FILE *fp, unsigned int map_idx) 393{ 394 struct mapping_list *ml = &maps[map_idx]; 395 struct mapping *mp; 396 struct file_mapping fm; 397 unsigned int i = 0, j = 0; 398 399 TAILQ_FOREACH(mp, ml, m_list) { 400 j++; 401 if (mp->m_length > 0) { 402 i += mp->m_length; 403 fm.source = htobe32(mp->m_char); 404 fm.destination = htobe16(mp->m_glyph->g_index); 405 fm.length = htobe16(mp->m_length - 1); 406 fwrite(&fm, sizeof fm, 1, fp); 407 } 408 } 409 assert(i == j); 410} 411 412struct file_header { 413 uint8_t magic[8]; 414 uint8_t width; 415 uint8_t height; 416 uint16_t pad; 417 uint32_t glyph_count; 418 uint32_t map_count[4]; 419} __packed; 420 421static int 422write_fnt(const char *filename) 423{ 424 FILE *fp; 425 struct file_header fh = { 426 .magic = "VFNT0002", 427 }; 428 429 fp = fopen(filename, "wb"); 430 if (fp == NULL) { 431 perror(filename); 432 return (1); 433 } 434 435 fh.width = width; 436 fh.height = height; 437 fh.glyph_count = htobe32(glyph_unique); 438 fh.map_count[0] = htobe32(map_folded_count[0]); 439 fh.map_count[1] = htobe32(map_folded_count[1]); 440 fh.map_count[2] = htobe32(map_folded_count[2]); 441 fh.map_count[3] = htobe32(map_folded_count[3]); 442 fwrite(&fh, sizeof fh, 1, fp); 443 444 write_glyphs(fp); 445 write_mappings(fp, VFNT_MAP_NORMAL); 446 write_mappings(fp, 1); 447 write_mappings(fp, VFNT_MAP_BOLD); 448 write_mappings(fp, 3); 449 450 return (0); 451} 452 453static void 454print_font_info(void) 455{ 456 printf( 457"Statistics:\n" 458"- glyph_total: %5u\n" 459"- glyph_normal: %5u\n" 460"- glyph_normal_right: %5u\n" 461"- glyph_bold: %5u\n" 462"- glyph_bold_right: %5u\n" 463"- glyph_unique: %5u\n" 464"- glyph_dupe: %5u\n" 465"- mapping_total: %5u\n" 466"- mapping_normal: %5u\n" 467"- mapping_normal_folded: %5u\n" 468"- mapping_normal_right: %5u\n" 469"- mapping_normal_right_folded: %5u\n" 470"- mapping_bold: %5u\n" 471"- mapping_bold_folded: %5u\n" 472"- mapping_bold_right: %5u\n" 473"- mapping_bold_right_folded: %5u\n" 474"- mapping_unique: %5u\n" 475"- mapping_dupe: %5u\n", 476 glyph_total, 477 glyph_count[0], 478 glyph_count[1], 479 glyph_count[2], 480 glyph_count[3], 481 glyph_unique, glyph_dupe, 482 mapping_total, 483 map_count[0], map_folded_count[0], 484 map_count[1], map_folded_count[1], 485 map_count[2], map_folded_count[2], 486 map_count[3], map_folded_count[3], 487 mapping_unique, mapping_dupe); 488} 489 490int 491main(int argc, char *argv[]) 492{ 493 int ch, val, verbose = 0; 494 495 assert(sizeof(struct file_header) == 32); 496 assert(sizeof(struct file_mapping) == 8); 497 498 while ((ch = getopt(argc, argv, "h:w:")) != -1) { 499 switch (ch) { 500 case 'h': 501 val = atoi(optarg); 502 if (val <= 0 || val > 128) { 503 errx(1, "Invalid height %d", val); 504 return (1); 505 } 506 height = val; 507 break; 508 case 'v': 509 verbose = 1; 510 break; 511 case 'w': 512 val = atoi(optarg); 513 if (val <= 0 || val > 128) { 514 errx(1, "Invalid width %d", val); 515 return (1); 516 } 517 width = val; 518 break; 519 case '?': 520 default: 521 usage(); 522 } 523 } 524 argc -= optind; 525 argv += optind; 526 527 if (argc < 2 || argc > 3) 528 usage(); 529 530 wbytes = howmany(width, 8); 531 532 if (parse_file(argv[0], VFNT_MAP_NORMAL) != 0) 533 return (1); 534 argc--; 535 argv++; 536 if (argc == 2) { 537 if (parse_file(argv[0], VFNT_MAP_BOLD) != 0) 538 return (1); 539 argc--; 540 argv++; 541 } 542 number_glyphs();
| 153static struct glyph * 154add_glyph(const uint8_t *bytes, unsigned int map_idx, int fallback) 155{ 156 struct glyph *gl; 157 int hash; 158 159 glyph_total++; 160 glyph_count[map_idx]++; 161 162 hash = fnv_32_buf(bytes, wbytes * height, FNV1_32_INIT) % FONTCVT_NHASH; 163 SLIST_FOREACH(gl, &glyph_hash[hash], g_hash) { 164 if (memcmp(gl->g_data, bytes, wbytes * height) == 0) { 165 glyph_dupe++; 166 return (gl); 167 } 168 } 169 170 gl = malloc(sizeof *gl); 171 gl->g_data = malloc(wbytes * height); 172 memcpy(gl->g_data, bytes, wbytes * height); 173 if (fallback) 174 TAILQ_INSERT_HEAD(&glyphs[map_idx], gl, g_list); 175 else 176 TAILQ_INSERT_TAIL(&glyphs[map_idx], gl, g_list); 177 SLIST_INSERT_HEAD(&glyph_hash[hash], gl, g_hash); 178 179 glyph_unique++; 180 return (gl); 181} 182 183static int 184add_char(unsigned curchar, unsigned map_idx, uint8_t *bytes, uint8_t *bytes_r) 185{ 186 struct glyph *gl; 187 188 /* Prevent adding two glyphs for 0xFFFD */ 189 if (curchar == 0xFFFD) { 190 if (map_idx < VFNT_MAP_BOLD) 191 gl = add_glyph(bytes, 0, 1); 192 } else if (curchar >= 0x20) { 193 gl = add_glyph(bytes, map_idx, 0); 194 if (add_mapping(gl, curchar, map_idx) != 0) 195 return (1); 196 if (bytes_r != NULL) { 197 gl = add_glyph(bytes_r, map_idx + 1, 0); 198 if (add_mapping(gl, curchar, 199 map_idx + 1) != 0) 200 return (1); 201 } 202 } 203 return (0); 204} 205 206 207static int 208parse_bitmap_line(uint8_t *left, uint8_t *right, unsigned int line, 209 unsigned int dwidth) 210{ 211 uint8_t *p; 212 unsigned int i, subline; 213 214 if (dwidth != width && dwidth != width * 2) { 215 errx(1, 216 "Bitmap with unsupported width %u!\n", dwidth); 217 return (1); 218 } 219 220 /* Move pixel data right to simplify splitting double characters. */ 221 line >>= (howmany(dwidth, 8) * 8) - dwidth; 222 223 for (i = dwidth / width; i > 0; i--) { 224 p = (i == 2) ? right : left; 225 226 subline = line & ((1 << width) - 1); 227 subline <<= (howmany(width, 8) * 8) - width; 228 229 if (wbytes == 1) { 230 *p = subline; 231 } else if (wbytes == 2) { 232 *p++ = subline >> 8; 233 *p = subline; 234 } else { 235 errx(1, 236 "Unsupported wbytes %u!\n", wbytes); 237 return (1); 238 } 239 240 line >>= width; 241 } 242 243 return (0); 244} 245 246static int 247parse_bdf(FILE *fp, unsigned int map_idx) 248{ 249 char *ln; 250 size_t length; 251 uint8_t bytes[wbytes * height], bytes_r[wbytes * height]; 252 unsigned int curchar = 0, dwidth = 0, i, line; 253 254 while ((ln = fgetln(fp, &length)) != NULL) { 255 ln[length - 1] = '\0'; 256 257 if (strncmp(ln, "ENCODING ", 9) == 0) { 258 curchar = atoi(ln + 9); 259 } 260 261 if (strncmp(ln, "DWIDTH ", 7) == 0) { 262 dwidth = atoi(ln + 7); 263 } 264 265 if (strncmp(ln, "BITMAP", 6) == 0 && 266 (ln[6] == ' ' || ln[6] == '\0')) { 267 for (i = 0; i < height; i++) { 268 if ((ln = fgetln(fp, &length)) == NULL) { 269 errx(1, "Unexpected EOF!\n"); 270 return (1); 271 } 272 ln[length - 1] = '\0'; 273 sscanf(ln, "%x", &line); 274 if (parse_bitmap_line(bytes + i * wbytes, 275 bytes_r + i * wbytes, line, dwidth) != 0) 276 return (1); 277 } 278 279 if (add_char(curchar, map_idx, bytes, 280 dwidth == width * 2 ? bytes_r : NULL) != 0) 281 return (1); 282 } 283 } 284 285 return (0); 286} 287 288static int 289parse_hex(FILE *fp, unsigned int map_idx) 290{ 291 char *ln, *p; 292 char fmt_str[8]; 293 size_t length; 294 uint8_t bytes[wbytes * height], bytes_r[wbytes * height]; 295 unsigned curchar = 0, i, line, chars_per_row, dwidth; 296 297 while ((ln = fgetln(fp, &length)) != NULL) { 298 ln[length - 1] = '\0'; 299 300 if (strncmp(ln, "# Height: ", 10) == 0) { 301 height = atoi(ln + 10); 302 } else if (strncmp(ln, "# Width: ", 9) == 0) { 303 width = atoi(ln + 9); 304 } else if (sscanf(ln, "%4x:", &curchar)) { 305 p = ln + 5; 306 chars_per_row = strlen(p) / height; 307 dwidth = width; 308 if (chars_per_row / 2 > width / 8) 309 dwidth *= 2; /* Double-width character. */ 310 snprintf(fmt_str, sizeof(fmt_str), "%%%ux", 311 chars_per_row); 312 313 for (i = 0; i < height; i++) { 314 sscanf(p, fmt_str, &line); 315 p += chars_per_row; 316 if (parse_bitmap_line(bytes + i * wbytes, 317 bytes_r + i * wbytes, line, dwidth) != 0) 318 return (1); 319 } 320 321 if (add_char(curchar, map_idx, bytes, 322 dwidth == width * 2 ? bytes_r : NULL) != 0) 323 return (1); 324 } 325 } 326 return (0); 327} 328 329static int 330parse_file(const char *filename, unsigned int map_idx) 331{ 332 FILE *fp; 333 size_t len; 334 335 fp = fopen(filename, "r"); 336 if (fp == NULL) { 337 perror(filename); 338 return (1); 339 } 340 len = strlen(filename); 341 if (len > 4 && strcasecmp(filename + len - 4, ".hex") == 0) 342 return parse_hex(fp, map_idx); 343 return parse_bdf(fp, map_idx); 344} 345 346static void 347number_glyphs(void) 348{ 349 struct glyph *gl; 350 unsigned int i, idx = 0; 351 352 for (i = 0; i < VFNT_MAPS; i++) 353 TAILQ_FOREACH(gl, &glyphs[i], g_list) 354 gl->g_index = idx++; 355} 356 357static void 358write_glyphs(FILE *fp) 359{ 360 struct glyph *gl; 361 unsigned int i; 362 363 for (i = 0; i < VFNT_MAPS; i++) { 364 TAILQ_FOREACH(gl, &glyphs[i], g_list) 365 fwrite(gl->g_data, wbytes * height, 1, fp); 366 } 367} 368 369static void 370fold_mappings(unsigned int map_idx) 371{ 372 struct mapping_list *ml = &maps[map_idx]; 373 struct mapping *mn, *mp, *mbase; 374 375 mp = mbase = TAILQ_FIRST(ml); 376 for (mp = mbase = TAILQ_FIRST(ml); mp != NULL; mp = mn) { 377 mn = TAILQ_NEXT(mp, m_list); 378 if (mn != NULL && mn->m_char == mp->m_char + 1 && 379 mn->m_glyph->g_index == mp->m_glyph->g_index + 1) 380 continue; 381 mbase->m_length = mp->m_char - mbase->m_char + 1; 382 mbase = mp = mn; 383 map_folded_count[map_idx]++; 384 } 385} 386 387struct file_mapping { 388 uint32_t source; 389 uint16_t destination; 390 uint16_t length; 391} __packed; 392 393static void 394write_mappings(FILE *fp, unsigned int map_idx) 395{ 396 struct mapping_list *ml = &maps[map_idx]; 397 struct mapping *mp; 398 struct file_mapping fm; 399 unsigned int i = 0, j = 0; 400 401 TAILQ_FOREACH(mp, ml, m_list) { 402 j++; 403 if (mp->m_length > 0) { 404 i += mp->m_length; 405 fm.source = htobe32(mp->m_char); 406 fm.destination = htobe16(mp->m_glyph->g_index); 407 fm.length = htobe16(mp->m_length - 1); 408 fwrite(&fm, sizeof fm, 1, fp); 409 } 410 } 411 assert(i == j); 412} 413 414struct file_header { 415 uint8_t magic[8]; 416 uint8_t width; 417 uint8_t height; 418 uint16_t pad; 419 uint32_t glyph_count; 420 uint32_t map_count[4]; 421} __packed; 422 423static int 424write_fnt(const char *filename) 425{ 426 FILE *fp; 427 struct file_header fh = { 428 .magic = "VFNT0002", 429 }; 430 431 fp = fopen(filename, "wb"); 432 if (fp == NULL) { 433 perror(filename); 434 return (1); 435 } 436 437 fh.width = width; 438 fh.height = height; 439 fh.glyph_count = htobe32(glyph_unique); 440 fh.map_count[0] = htobe32(map_folded_count[0]); 441 fh.map_count[1] = htobe32(map_folded_count[1]); 442 fh.map_count[2] = htobe32(map_folded_count[2]); 443 fh.map_count[3] = htobe32(map_folded_count[3]); 444 fwrite(&fh, sizeof fh, 1, fp); 445 446 write_glyphs(fp); 447 write_mappings(fp, VFNT_MAP_NORMAL); 448 write_mappings(fp, 1); 449 write_mappings(fp, VFNT_MAP_BOLD); 450 write_mappings(fp, 3); 451 452 return (0); 453} 454 455static void 456print_font_info(void) 457{ 458 printf( 459"Statistics:\n" 460"- glyph_total: %5u\n" 461"- glyph_normal: %5u\n" 462"- glyph_normal_right: %5u\n" 463"- glyph_bold: %5u\n" 464"- glyph_bold_right: %5u\n" 465"- glyph_unique: %5u\n" 466"- glyph_dupe: %5u\n" 467"- mapping_total: %5u\n" 468"- mapping_normal: %5u\n" 469"- mapping_normal_folded: %5u\n" 470"- mapping_normal_right: %5u\n" 471"- mapping_normal_right_folded: %5u\n" 472"- mapping_bold: %5u\n" 473"- mapping_bold_folded: %5u\n" 474"- mapping_bold_right: %5u\n" 475"- mapping_bold_right_folded: %5u\n" 476"- mapping_unique: %5u\n" 477"- mapping_dupe: %5u\n", 478 glyph_total, 479 glyph_count[0], 480 glyph_count[1], 481 glyph_count[2], 482 glyph_count[3], 483 glyph_unique, glyph_dupe, 484 mapping_total, 485 map_count[0], map_folded_count[0], 486 map_count[1], map_folded_count[1], 487 map_count[2], map_folded_count[2], 488 map_count[3], map_folded_count[3], 489 mapping_unique, mapping_dupe); 490} 491 492int 493main(int argc, char *argv[]) 494{ 495 int ch, val, verbose = 0; 496 497 assert(sizeof(struct file_header) == 32); 498 assert(sizeof(struct file_mapping) == 8); 499 500 while ((ch = getopt(argc, argv, "h:w:")) != -1) { 501 switch (ch) { 502 case 'h': 503 val = atoi(optarg); 504 if (val <= 0 || val > 128) { 505 errx(1, "Invalid height %d", val); 506 return (1); 507 } 508 height = val; 509 break; 510 case 'v': 511 verbose = 1; 512 break; 513 case 'w': 514 val = atoi(optarg); 515 if (val <= 0 || val > 128) { 516 errx(1, "Invalid width %d", val); 517 return (1); 518 } 519 width = val; 520 break; 521 case '?': 522 default: 523 usage(); 524 } 525 } 526 argc -= optind; 527 argv += optind; 528 529 if (argc < 2 || argc > 3) 530 usage(); 531 532 wbytes = howmany(width, 8); 533 534 if (parse_file(argv[0], VFNT_MAP_NORMAL) != 0) 535 return (1); 536 argc--; 537 argv++; 538 if (argc == 2) { 539 if (parse_file(argv[0], VFNT_MAP_BOLD) != 0) 540 return (1); 541 argc--; 542 argv++; 543 } 544 number_glyphs();
|