termfont.c (19706B)
1 #! /usr/bin/env sheepy 2 /* or direct path to sheepy: #! /usr/local/bin/sheepy */ 3 4 // ANSI Regular.flf ANSI Shadow.flf DOS Rebel.flf 5 // https://www.fontspace.com/withheld-data-font-f29245 6 // https://www.fontspace.com/computer-pixel-7-font-f15539 7 // https://www.fontspace.com/pxlvetica-font-f16197 8 // https://www.fontspace.com/trs-80-coconut-font-f29856 9 // https://www.fontspace.com/shylock-nbp-font-f15144 10 // https://www.fontspace.com/guru-meditation-nbp-font-f15920 11 // https://www.fontspace.com/bittypix-monospace-font-f29160 12 // https://www.fontspace.com/g7-star-force-font-f5955 13 // https://www.fontspace.com/inky-thin-pixels-font-f28123 14 // https://www.fontspace.com/public-pixel-font-f72305 15 // https://www.fontspace.com/hachicro-undertale-font-f83280 16 // https://www.fontspace.com/pixgamer-font-f85447 17 // https://www.fontspace.com/pixeloid-font-f69232 18 // https://www.fontspace.com/minecraft-font-f28180 19 // https://www.fontspace.com/press-start-2p-font-f11591 20 // https://www.fontspace.com/jogan-soft-font-f80664 21 // https://www.fontspace.com/pixel-emulator-font-f21507 22 // https://www.fontspace.com/determination-mono-web-font-f23209 23 // https://www.fontspace.com/lcd-solid-font-f11346 24 // https://www.fontspace.com/nineteen-ninety-seven-font-f29655 25 // https://www.fontspace.com/old-school-adventures-font-f26494 26 // https://www.fontspace.com/edit-undo-brk-font-f19980 27 // https://www.fontspace.com/mozart-nbp-font-f18977 28 // https://www.fontspace.com/mecha-font-f13151 29 // https://www.fontspace.com/gamegirl-classic-font-f3331 30 // https://www.fontspace.com/thin-pixel-7-font-f16064 31 // https://www.fontspace.com/connection-serif-font-f26406 32 // https://www.fontspace.com/warioland4tt-font-f30199 33 // https://www.fontspace.com/teeny-tiny-pixls-font-f30095 34 // convert -background none -fill black -font font.ttf -pointsize 300 label:"Z" z.png 35 // convert file txt:- 36 37 /* Libsheepy documentation: https://spartatek.se/libsheepy/ */ 38 #include "libsheepyObject.h" 39 40 #define FONT_DIR "~/.termfont/" 41 42 int argc; char **argv; 43 44 /* enable/disable logging */ 45 /* #undef pLog */ 46 /* #define pLog(...) */ 47 48 typ struct { 49 u32 width; 50 u8 *pixels; 51 } symbol; 52 53 typ struct { 54 bool pixel; 55 u32 height; 56 symbol chars[127]; 57 u8 *pixels; 58 } twidfont; 59 60 bool parseTwidFont(smallArrayt *fontFile, twidfont *font) { 61 62 // scan symbol sizes 63 // create pixel buffer 64 // copy font to pixel buffer 65 66 // scan symbol sizes 67 u32 totalWidth = 0; 68 u8 index = 0; 69 bool scanHeight = yes; 70 char *status = "pixel"; 71 iter(fontFile, L) { 72 castS(l, L); 73 if (eqG(status, "in char")) { 74 if (font->chars[index].width == 0) { 75 font->chars[index].width = indexOfG(l, "@"); 76 totalWidth += font->chars[index].width; 77 } 78 if (scanHeight) inc font->height; 79 if (endsWithG(l, "@@")) { 80 // char is finished 81 scanHeight = no; 82 status = "define char"; 83 continue; 84 } 85 } 86 if (eqG(status, "define char")) { 87 defineChar: 88 index = ssGet(l)[0]; 89 status = "in char"; 90 } 91 if (eqG(status, "pixel")) { 92 if (ssGet(l)[0] == '#') continue; // comment at the begining 93 font->pixel = eqG(l, "pixel"); 94 if (not font->pixel) goto defineChar; // already define char 95 status = "define char"; 96 } 97 } 98 //logVarG(totalWidth); 99 100 // create pixel buffer 101 font->pixels = malloc(font->height * totalWidth); 102 103 // copy font to pixel buffer 104 u8 *symbolStart = font->pixels; 105 u8 *p; // pointer for copying symbol pixel data 106 status = "pixel"; 107 iter(fontFile, L) { 108 castS(l, L); 109 if (eqG(status, "in char")) { 110 if (!font->chars[index].pixels) { 111 // set pointer in pixel buffer for symbol 112 font->chars[index].pixels = symbolStart; 113 p = symbolStart; 114 symbolStart += font->height * font->chars[index].width; 115 } 116 memcpy(p, ssGet(l), font->chars[index].width); 117 p += font->chars[index].width; 118 if (endsWithG(l, "@@")) { 119 // char is finished 120 scanHeight = no; 121 status = "define char"; 122 continue; 123 } 124 } 125 if (eqG(status, "define char")) { 126 defineChar2: 127 index = ssGet(l)[0]; 128 status = "in char"; 129 } 130 if (eqG(status, "pixel")) { 131 if (ssGet(l)[0] == '#') continue; // comment at the begining 132 font->pixel = eqG(l, "pixel"); 133 if (not font->pixel) goto defineChar2; // already define char 134 status = "define char"; 135 } 136 } 137 138 ret yes; 139 } 140 141 void freeTwidFont(twidfont *font) { 142 if (font) freen(font->pixels); 143 } 144 145 void showRawSymbol(twidfont *font, u32 index) { 146 if (!font) ret; 147 u8 line[font->chars[index].width +1]; 148 line[font->chars[index].width] = 0; 149 150 u8 *p = font->chars[index].pixels; 151 range(i, font->height) { 152 memcpy(line, p, font->chars[index].width); 153 p += font->chars[index].width; 154 puts(line); 155 } 156 } 157 158 // bit 0 is the lower line 159 // bit 1 is the upper line 160 // ▄ 0x2584 ▀ 0x2580 █ 0x2588 161 char *halfBlocks[] = {" ", "▄", "▀", "█"}; 162 163 void showSymbolHalfBlock(twidfont *font, u32 index) { 164 if (!font or !font->pixel) ret; 165 166 u8 *p = font->chars[index].pixels; 167 rangeFromStep(j, 1, font->height, 2) { 168 u8 block = 0; 169 range(i, font->chars[index].width) { 170 block = (*(p + i)== ' ' ? 0 : 2) | (*(p + i + font->chars[index].width)== ' ' ? 0 : 1); 171 printf(halfBlocks[block]); 172 } 173 put; 174 p += font->chars[index].width * 2; 175 } 176 if (font->height & 1) { 177 u8 block = 0; 178 range(i, font->chars[index].width) { 179 block = (*(p + i)== ' ' ? 0 : 2); 180 printf(halfBlocks[block]); 181 } 182 put; 183 } 184 } 185 186 // bits 3|2 187 // --- 188 // 1|0 189 // ▗ 0x2597 ▖ 0x2596 ▄ 0x2584 ▝ 0x259D ▐ 0x2590 ▞ 0x259E ▟ 0x259F ▘ 0x2598 190 // ▚ 0x259A ▌ 0x258C ▙ 0x2599 ▀ 0x2580 ▜ 0x259C ▛ 0x259B █ 0x2588 191 char *quadrants[] = {" ", "▗", "▖", "▄", "▝", "▐", "▞", "▟", "▘", "▚", "▌", "▙", "▀", "▜", "▛", "█"}; 192 193 void showSymbolQuadrant(twidfont *font, u32 index) { 194 if (!font or !font->pixel) ret; 195 196 u8 *p = font->chars[index].pixels; 197 rangeFromStep(j, 1, font->height, 2) { 198 u8 block = 0; 199 rangeFromStep(i, 1, font->chars[index].width, 2) { 200 block = (*(p + i-1) == ' ' ? 0 : 8) 201 | (*(p + i) == ' ' ? 0 : 4) 202 | (*(p + i-1 + font->chars[index].width) == ' ' ? 0 : 2) 203 | (*(p + i + font->chars[index].width) == ' ' ? 0 : 1); 204 printf(quadrants[block]); 205 } 206 if (font->chars[index].width & 1) { 207 block = (*(p + font->chars[index].width-1) == ' ' ? 0 : 8) 208 | (*(p + font->chars[index].width-1 + font->chars[index].width) == ' ' ? 0 : 2); 209 printf(quadrants[block]); 210 } 211 put; 212 p += font->chars[index].width * 2; 213 } 214 if (font->height & 1) { 215 u8 block = 0; 216 range(i, font->chars[index].width) { 217 block = (*(p + i)== ' ' ? 0 : 2); 218 printf(halfBlocks[block]); 219 } 220 put; 221 } 222 } 223 224 void showStringRaw(twidfont *font, char *string) { 225 if (!font or font->pixel) ret; 226 size_t len = lenG(string); 227 if (!len) ret; 228 229 u32 totalWidth = 0; // in blocks 230 range(i, len) { 231 totalWidth += font->chars[string[i]].width; 232 } 233 234 totalWidth += 1; // for line returns and end of string 235 236 u8 *pixels = malloc(font->height * totalWidth); 237 u32 x = 0; // start of next character in pixels 238 239 range(i, len) { 240 if (!font->chars[string[i]].width) continue; // font symbol unavailable 241 // copy symbol to buffer 242 u8 *p = font->chars[string[i]].pixels; 243 range(ii, font->height) { 244 memcpy(pixels + x + ii * totalWidth, p, font->chars[string[i]].width); 245 p += font->chars[string[i]].width; 246 } 247 248 x+= font->chars[string[i]].width; 249 } 250 range(i, font->height-1) { 251 *(pixels + totalWidth -1 + i * totalWidth) = '\n'; 252 } 253 *(pixels + totalWidth -1 + (font->height-1) * totalWidth) = 0; 254 255 printf(pixels); 256 put 257 258 free(pixels); 259 } 260 261 void showStringHalfblock(twidfont *font, char *string) { 262 if (!font or !font->pixel) ret; 263 size_t len = lenG(string); 264 if (!len) ret; 265 266 u32 totalWidth = 0; // in blocks 267 range(i, len) { 268 totalWidth += font->chars[string[i]].width; 269 } 270 271 u8 *pixels = malloc(font->height * totalWidth); 272 u32 x = 0; // start of next character in pixels 273 274 range(i, len) { 275 if (!font->chars[string[i]].width) continue; // font symbol unavailable 276 // copy symbol to buffer 277 u8 *p = font->chars[string[i]].pixels; 278 range(ii, font->height) { 279 memcpy(pixels + x + ii * totalWidth, p, font->chars[string[i]].width); 280 p += font->chars[string[i]].width; 281 } 282 283 x+= font->chars[string[i]].width; 284 } 285 286 u8 *p = pixels; 287 rangeFromStep(j, 1, font->height, 2) { 288 u8 block = 0; 289 range(i, totalWidth) { 290 block = (*(p + i)== ' ' ? 0 : 2) | (*(p + i + totalWidth)== ' ' ? 0 : 1); 291 printf(halfBlocks[block]); 292 } 293 put; 294 p += totalWidth * 2; 295 } 296 if (font->height & 1) { 297 u8 block = 0; 298 range(i, totalWidth) { 299 block = (*(p + i)== ' ' ? 0 : 2); 300 printf(halfBlocks[block]); 301 } 302 put; 303 } 304 305 /* u32 *buffer = malloc( (font->height/2 + font->height&1) */ 306 /* * ( totalWidth) */ 307 /* * sizeof(u32)); */ 308 /* free(buffer); */ 309 free(pixels); 310 } 311 312 void showStringHalfblockNoFullBlock(twidfont *font, char *string) { 313 if (!font or !font->pixel) ret; 314 size_t len = lenG(string); 315 if (!len) ret; 316 317 u32 totalWidth = 0; // in blocks 318 range(i, len) { 319 totalWidth += font->chars[string[i]].width; 320 } 321 322 u8 *pixels = malloc(font->height * totalWidth); 323 u32 x = 0; // start of next character in pixels 324 325 range(i, len) { 326 if (!font->chars[string[i]].width) continue; // font symbol unavailable 327 // copy symbol to buffer 328 u8 *p = font->chars[string[i]].pixels; 329 range(ii, font->height) { 330 memcpy(pixels + x + ii * totalWidth, p, font->chars[string[i]].width); 331 p += font->chars[string[i]].width; 332 } 333 334 x+= font->chars[string[i]].width; 335 } 336 337 u32 colors[] = {0x4495cc, 0x6baddb, 0xcceafe, 0xd4eefd, 0x896215, 0xd49b33, 0xe3b248, 0xfee2a4}; 338 339 u8 *p = pixels; 340 rangeFromStep(j, 1, font->height, 2) { 341 range(i, totalWidth) { 342 if (*(p + i)== ' ') 343 printf("%k",0); 344 else 345 printf("%k", colors[j-1]); 346 if (*(p + i + totalWidth)== ' ') 347 printf("%K", 0); 348 else 349 printf("%K", colors[j]); 350 printf(halfBlocks[2]); 351 } 352 printf(RST); 353 put; 354 p += totalWidth * 2; 355 } 356 if (font->height & 1) { 357 range(i, totalWidth) { 358 if (*(p + i)== ' ') 359 printf("%k",0); 360 else 361 printf("%k", colors[j-1]); 362 printf(halfBlocks[2]); 363 printf(RST); 364 } 365 put; 366 } 367 368 /* u32 *buffer = malloc( (font->height/2 + font->height&1) */ 369 /* * ( totalWidth) */ 370 /* * sizeof(u32)); */ 371 /* free(buffer); */ 372 free(pixels); 373 } 374 375 void showStringQuadrant(twidfont *font, char *string) { 376 if (!font or !font->pixel) ret; 377 size_t len = lenG(string); 378 if (!len) ret; 379 380 u32 totalWidth = 0; // in blocks 381 range(i, len) { 382 totalWidth += font->chars[string[i]].width; 383 } 384 385 u8 *pixels = malloc(font->height * totalWidth); 386 u32 x = 0; // start of next character in pixels 387 388 range(i, len) { 389 if (!font->chars[string[i]].width) continue; // font symbol unavailable 390 // copy symbol to buffer 391 u8 *p = font->chars[string[i]].pixels; 392 range(ii, font->height) { 393 memcpy(pixels + x + ii * totalWidth, p, font->chars[string[i]].width); 394 p += font->chars[string[i]].width; 395 } 396 397 x+= font->chars[string[i]].width; 398 } 399 400 u8 *p = pixels; 401 rangeFromStep(j, 1, font->height, 2) { 402 u8 block = 0; 403 rangeFromStep(i, 1, totalWidth, 2) { 404 block = (*(p + i-1) == ' ' ? 0 : 8) 405 | (*(p + i) == ' ' ? 0 : 4) 406 | (*(p + i-1 + totalWidth) == ' ' ? 0 : 2) 407 | (*(p + i + totalWidth) == ' ' ? 0 : 1); 408 printf(quadrants[block]); 409 } 410 if (totalWidth & 1) { 411 block = (*(p + totalWidth-1) == ' ' ? 0 : 8) 412 | (*(p + totalWidth-1 + totalWidth) == ' ' ? 0 : 2); 413 printf(quadrants[block]); 414 } 415 put; 416 p += totalWidth * 2; 417 } 418 if (font->height & 1) { 419 u8 block = 0; 420 rangeFromStep(i, 1, totalWidth, 2) { 421 block = (*(p + i-1) == ' ' ? 0 : 8) 422 | (*(p + i) == ' ' ? 0 : 4); 423 printf(quadrants[block]); 424 } 425 if (totalWidth & 1) { 426 block = (*(p + totalWidth-1) == ' ' ? 0 : 8); 427 printf(quadrants[block]); 428 } 429 put; 430 } 431 432 /* u32 *buffer = malloc( (font->height/2 + font->height&1) */ 433 /* * ( totalWidth/2 + totalWidth&1) */ 434 /* * sizeof(u32)); */ 435 /* free(buffer); */ 436 free(pixels); 437 } 438 439 void showStringQuadrantColors(twidfont *font, char *string) { 440 if (!font or !font->pixel) ret; 441 size_t len = lenG(string); 442 if (!len) ret; 443 444 u32 totalWidth = 0; // in blocks 445 range(i, len) { 446 totalWidth += font->chars[string[i]].width; 447 } 448 449 u8 *pixels = malloc(font->height * totalWidth); 450 u32 x = 0; // start of next character in pixels 451 452 range(i, len) { 453 if (!font->chars[string[i]].width) continue; // font symbol unavailable 454 // copy symbol to buffer 455 u8 *p = font->chars[string[i]].pixels; 456 range(ii, font->height) { 457 memcpy(pixels + x + ii * totalWidth, p, font->chars[string[i]].width); 458 p += font->chars[string[i]].width; 459 } 460 461 x+= font->chars[string[i]].width; 462 } 463 464 u32 colors[] = {0x4495cc, 0xd4eefd, 0xd49b33, 0xecc778}; 465 466 u8 *p = pixels; 467 rangeFromStep(j, 1, font->height, 2) { 468 u8 block = 0; 469 printf("%k", colors[j/2]); 470 rangeFromStep(i, 1, totalWidth, 2) { 471 block = (*(p + i-1) == ' ' ? 0 : 8) 472 | (*(p + i) == ' ' ? 0 : 4) 473 | (*(p + i-1 + totalWidth) == ' ' ? 0 : 2) 474 | (*(p + i + totalWidth) == ' ' ? 0 : 1); 475 printf(quadrants[block]); 476 } 477 if (totalWidth & 1) { 478 block = (*(p + totalWidth-1) == ' ' ? 0 : 8) 479 | (*(p + totalWidth-1 + totalWidth) == ' ' ? 0 : 2); 480 printf(quadrants[block]); 481 } 482 printf(RST); 483 put; 484 p += totalWidth * 2; 485 } 486 if (font->height & 1) { 487 u8 block = 0; 488 printf("%k", colors[font->height/2]); 489 rangeFromStep(i, 1, totalWidth, 2) { 490 block = (*(p + i-1) == ' ' ? 0 : 8) 491 | (*(p + i) == ' ' ? 0 : 4); 492 printf(quadrants[block]); 493 } 494 if (totalWidth & 1) { 495 block = (*(p + totalWidth-1) == ' ' ? 0 : 8); 496 printf(quadrants[block]); 497 } 498 printf(RST); 499 put; 500 } 501 502 /* u32 *buffer = malloc( (font->height/2 + font->height&1) */ 503 /* * ( totalWidth/2 + totalWidth&1) */ 504 /* * sizeof(u32)); */ 505 /* free(buffer); */ 506 free(pixels); 507 } 508 509 void list(void) { 510 cleanCharP(p) = expandHome(FONT_DIR); 511 cleanSmallArrayP(dir) = readDirG(rtSmallArrayt, p); 512 513 iter(dir, L) { 514 castS(l,L); 515 if (endsWithG(l, ".twidf")) { 516 setG(l, -6, 0); 517 logI("%m", l); 518 } 519 } 520 } 521 void demo(void) { 522 cleanCharP(p) = expandHome(FONT_DIR); 523 cleanSmallArrayP(dir) = readDirG(rtSmallArrayt, p); 524 525 iter(dir, L) { 526 castS(l,L); 527 if (endsWithG(l, ".twidf")) { 528 cleanAllocateSmallArray(fontFile); 529 readFileG(fontFile, l); 530 setG(l, -6, 0); 531 logI("%m", l); 532 twidfont font = init0Var; 533 parseTwidFont(fontFile, &font); 534 if (not font.pixel) 535 showStringRaw(&font, "0123 abcd ABCD"); 536 else { 537 showStringQuadrant(&font, "0123 abcd ABCD"); 538 showStringHalfblock(&font, "0123 abcd ABCD"); 539 } 540 freeTwidFont(&font); 541 } 542 } 543 } 544 545 int main(int ARGC, char** ARGV) { 546 547 argc = ARGC; argv = ARGV; 548 549 initLibsheepy(ARGV[0]); 550 setLogMode(LOG_VOID); 551 //openProgLogFile(); 552 //setLogSymbols(LOG_UTF8); 553 //disableLibsheepyErrorLogs; 554 555 if ((argc == 1) or 556 (argc == 4 and not eqG(argv[1], "-f") and not eqG(argv[1], "-F"))) { 557 help: 558 logI("Help\n" 559 "Commands:\n" 560 BLD CYN"list"RST" to list available fonts in "FONT_DIR"\n" 561 BLD CYN"demo"RST" to print a short string with all available fonts\n" 562 BLD CYN"-f font name (without .twidf) 'Message'"RST" to show message with the selected font rendered with quadrants\n" 563 BLD CYN"-F font name (without .twidf) 'Message'"RST" to show message with the selected font rendered with halfblocks\n" 564 BLD CYN"color 'Message'"RST" to show message with the PressStart2P halfblock with colors\n" 565 BLD CYN"help, -h or --help"RST" for help"); 566 ret 0; 567 } 568 if (argc == 2) { 569 if (eqG(argv[1], "help") or eqG(argv[1], "--help") or eqG(argv[1], "-h")) goto help; 570 elif (eqG(argv[1], "list")) { 571 list(); 572 ret 0; 573 } 574 elif (eqG(argv[1], "demo")) { 575 demo(); 576 ret 0; 577 } 578 goto help; 579 } 580 581 if (argc == 3) { 582 if (eqG(argv[1], "color")) { 583 cleanAllocateSmallArray(fontFile); 584 cleanCharP(p) = expandHome(FONT_DIR"PressStart2P.twidf"); 585 readFileG(fontFile, p); 586 587 twidfont font = init0Var; 588 589 parseTwidFont(fontFile, &font); 590 591 showStringHalfblockNoFullBlock(&font, argv[2]); 592 593 freeTwidFont(&font); 594 ret 0; 595 } 596 goto help; 597 } 598 599 cleanCharP(fontname) = catS(argv[2], ".twidf"); 600 if (not isPath(fontname)) { 601 freen(fontname); 602 cleanCharP(p) = catS(FONT_DIR, argv[2], ".twidf"); 603 fontname = expandHome(p); 604 if (not isPath(fontname)) { 605 logE("Font file not found: %s", argv[2]); 606 ret 1; 607 } 608 } 609 610 cleanAllocateSmallArray(fontFile); 611 readFileG(fontFile, fontname); 612 613 twidfont font = init0Var; 614 615 parseTwidFont(fontFile, &font); 616 617 if (not font.pixel) 618 showStringRaw(&font, argv[3]); 619 elif (eqG(argv[1], "-f")) 620 showStringQuadrant(&font, argv[3]); 621 elif (eqG(argv[1], "-F")) 622 showStringHalfblock(&font, argv[3]); 623 624 freeTwidFont(&font); 625 ret 0; 626 627 { 628 cleanAllocateSmallArray(fontFile); 629 //readFileG(fontFile, "WithheldData.twidf"); 630 //readFileG(fontFile, "Warioland.twidf"); 631 readFileG(fontFile, "PressStart2P.twidf"); 632 // TODO readFileG(fontFile, "hazeltine.twidf"); 633 634 twidfont font = init0Var; 635 636 parseTwidFont(fontFile, &font); 637 638 logI("Font height %d", font.height); 639 640 arange(i, font.chars) { 641 if (font.chars[i].width) { 642 //showSymbolQuadrant(&font, i); 643 showRawSymbol(&font, i); 644 } 645 } 646 647 /* showRawSymbol(&font, '#'); */ 648 /* showRawSymbol(&font, '