termfont

Display characters with unicode quadrants and halfblock
git clone https://noulin.net/git/termfont.git
Log | Files | Refs

termfont.c (25287B)


      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[font->height-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 showString2by3(twidfont *font, char *string) {
    510   if (!font or !font->pixel) ret;
    511   size_t len = lenG(string);
    512   if (!len) ret;
    513 
    514   u32 totalWidth = 0; // in blocks
    515   range(i, len) {
    516     totalWidth += font->chars[string[i]].width;
    517   }
    518 
    519   u8 *pixels  = malloc(font->height * totalWidth);
    520   u32 x       = 0; // start of next character in pixels
    521 
    522   range(i, len) {
    523     if (!font->chars[string[i]].width) continue; // font symbol unavailable
    524     // copy symbol to buffer
    525     u8 *p = font->chars[string[i]].pixels;
    526     range(ii, font->height) {
    527       memcpy(pixels + x + ii * totalWidth, p, font->chars[string[i]].width);
    528       p += font->chars[string[i]].width;
    529     }
    530 
    531     x+= font->chars[string[i]].width;
    532   }
    533 
    534   u8 *p       = pixels;
    535   char utf[6] = init0Var;
    536   u32 block;
    537   rangeFromStep(j, 2, font->height, 3) {
    538     rangeFromStep(i, 1, totalWidth, 2) {
    539       block = 0;
    540       if (*(p + i-1)                != ' ') block |= 1;
    541       if (*(p + i)                  != ' ') block |= 2;
    542       if (*(p + i-1 + totalWidth)   != ' ') block |= 4;
    543       if (*(p + i   + totalWidth)   != ' ') block |= 8;
    544       if (*(p + i-1 + 2*totalWidth) != ' ') block |= 16;
    545       if (*(p + i   + 2*totalWidth) != ' ') block |= 32;
    546       if   (block == 0)    block = ' ';
    547       elif (block == 0x3f) block = 0x2588;
    548       elif (block < 0x15)  block = block-1 + 0x1fb00;
    549       elif (block == 0x15) block = 0x258c;
    550       elif (block < 0x2a)  block = block-2 + 0x1fb00;
    551       elif (block == 0x2a) block = 0x2590;
    552       else                   block = block-3 + 0x1fb00;
    553       // vertical bar left 0x258c right 0x2590
    554       pError0(bRune2CodeUTF8(utf, block));
    555       printf(utf);
    556     }
    557     if (totalWidth & 1) {
    558       block = 0;
    559       if (*(p + totalWidth-1)                != ' ') block |= 1;
    560       if (*(p + totalWidth-1 + totalWidth)   != ' ') block |= 4;
    561       if (*(p + totalWidth-1 + 2*totalWidth) != ' ') block |= 16;
    562       if   (block == 0)    block = ' ';
    563       elif (block == 0x3f) block = 0x2588;
    564       elif (block < 0x15)  block = block-1 + 0x1fb00;
    565       elif (block == 0x15) block = 0x258c;
    566       elif (block < 0x2a)  block = block-2 + 0x1fb00;
    567       elif (block == 0x2a) block = 0x2590;
    568       else                   block = block-3 + 0x1fb00;
    569       // vertical bar left 0x258c right 0x2590
    570       pError0(bRune2CodeUTF8(utf, block));
    571       printf(utf);
    572     }
    573     put;
    574     p += totalWidth * 3;
    575   }
    576   if (font->height % 3 == 1) {
    577     // one more line
    578     rangeFromStep(i, 1, totalWidth, 2) {
    579       block = 0;
    580       if (*(p + i-1)                != ' ') block |= 1;
    581       if (*(p + i)                  != ' ') block |= 2;
    582       if   (block == 0)    block = ' ';
    583       elif (block == 0x3f) block = 0x2588;
    584       elif (block < 0x15)  block = block-1 + 0x1fb00;
    585       elif (block == 0x15) block = 0x258c;
    586       elif (block < 0x2a)  block = block-2 + 0x1fb00;
    587       elif (block == 0x2a) block = 0x2590;
    588       else                   block = block-3 + 0x1fb00;
    589       // vertical bar left 0x258c right 0x2590
    590       pError0(bRune2CodeUTF8(utf, block));
    591       printf(utf);
    592     }
    593     if (totalWidth & 1) {
    594       block = 0;
    595       if (*(p + totalWidth-1)                != ' ') block |= 1;
    596       if   (block == 0)    block = ' ';
    597       elif (block == 0x3f) block = 0x2588;
    598       elif (block < 0x15)  block = block-1 + 0x1fb00;
    599       elif (block == 0x15) block = 0x258c;
    600       elif (block < 0x2a)  block = block-2 + 0x1fb00;
    601       elif (block == 0x2a) block = 0x2590;
    602       else                   block = block-3 + 0x1fb00;
    603       // vertical bar left 0x258c right 0x2590
    604       pError0(bRune2CodeUTF8(utf, block));
    605       printf(utf);
    606     }
    607     put;
    608   }
    609   if (font->height % 3 == 2) {
    610     // two more lines
    611     rangeFromStep(i, 1, totalWidth, 2) {
    612       block = 0;
    613       if (*(p + i-1)                != ' ') block |= 1;
    614       if (*(p + i)                  != ' ') block |= 2;
    615       if (*(p + i-1 + totalWidth)   != ' ') block |= 4;
    616       if (*(p + i   + totalWidth)   != ' ') block |= 8;
    617       if   (block == 0)    block = ' ';
    618       elif (block == 0x3f) block = 0x2588;
    619       elif (block < 0x15)  block = block-1 + 0x1fb00;
    620       elif (block == 0x15) block = 0x258c;
    621       elif (block < 0x2a)  block = block-2 + 0x1fb00;
    622       elif (block == 0x2a) block = 0x2590;
    623       else                   block = block-3 + 0x1fb00;
    624       // vertical bar left 0x258c right 0x2590
    625       pError0(bRune2CodeUTF8(utf, block));
    626       printf(utf);
    627     }
    628     if (totalWidth & 1) {
    629       block = 0;
    630       if (*(p + totalWidth-1)                != ' ') block |= 1;
    631       if (*(p + totalWidth-1 + totalWidth)   != ' ') block |= 4;
    632       if   (block == 0)    block = ' ';
    633       elif (block == 0x3f) block = 0x2588;
    634       elif (block < 0x15)  block = block-1 + 0x1fb00;
    635       elif (block == 0x15) block = 0x258c;
    636       elif (block < 0x2a)  block = block-2 + 0x1fb00;
    637       elif (block == 0x2a) block = 0x2590;
    638       else                   block = block-3 + 0x1fb00;
    639       // vertical bar left 0x258c right 0x2590
    640       pError0(bRune2CodeUTF8(utf, block));
    641       printf(utf);
    642     }
    643     put;
    644   }
    645 
    646   /* u32 *buffer = malloc(  (font->height/2 + font->height&1) */
    647   /*                      * (  totalWidth/2 + totalWidth&1) */
    648   /*                      * sizeof(u32)); */
    649   /* free(buffer); */
    650   free(pixels);
    651 }
    652 
    653 void list(void) {
    654   cleanCharP(p)         = expandHome(FONT_DIR);
    655   cleanSmallArrayP(dir) = readDirG(rtSmallArrayt, p);
    656 
    657   iter(dir, L) {
    658     castS(l,L);
    659     if (endsWithG(l, ".twidf")) {
    660       setG(l, -6, 0);
    661       logI("%m", l);
    662     }
    663   }
    664 }
    665 void demo(void) {
    666   cleanCharP(p)         = expandHome(FONT_DIR);
    667   cleanSmallArrayP(dir) = readDirG(rtSmallArrayt, p);
    668 
    669   iter(dir, L) {
    670     castS(l,L);
    671     if (endsWithG(l, ".twidf")) {
    672       cleanAllocateSmallArray(fontFile);
    673       readFileG(fontFile, l);
    674       setG(l, -6, 0);
    675       twidfont font = init0Var;
    676       parseTwidFont(fontFile, &font);
    677       logI("%m h=%d mod3=%d", l, font.height, font.height % 3);
    678       if (not font.pixel)
    679         showStringRaw(&font,  "0123 abcd ABCD");
    680       else {
    681         showString2by3(&font, "0123 abcd ABCD");
    682         showStringQuadrant(&font, "0123 abcd ABCD");
    683         showStringHalfblock(&font, "0123 abcd ABCD");
    684       }
    685       freeTwidFont(&font);
    686     }
    687   }
    688 }
    689 
    690 int main(int ARGC, char** ARGV) {
    691 
    692   argc = ARGC; argv = ARGV;
    693 
    694   initLibsheepy(ARGV[0]);
    695   setLogMode(LOG_VOID);
    696   //openProgLogFile();
    697   //setLogSymbols(LOG_UTF8);
    698   //disableLibsheepyErrorLogs;
    699 
    700   if ((argc == 1) or
    701       (argc == 4 and not eqG(argv[1], "-s") and not eqG(argv[1], "-f") and not eqG(argv[1], "-F"))) {
    702     help:
    703     logI("Help\n"
    704          "Commands:\n"
    705          BLD CYN"list"RST"                                    to list available fonts in "FONT_DIR"\n"
    706          BLD CYN"demo"RST"                                    to print a short string with all available fonts\n"
    707          BLD CYN"-s font name (without .twidf) 'Message'"RST" to show message with the selected font rendered with 2 by 3 blocks\n"
    708          BLD CYN"-f font name (without .twidf) 'Message'"RST" to show message with the selected font rendered with quadrants\n"
    709          BLD CYN"-F font name (without .twidf) 'Message'"RST" to show message with the selected font rendered with halfblocks\n"
    710          BLD CYN"color 'Message'"RST"                         to show message with the PressStart2P halfblock with colors\n"
    711          BLD CYN"help, -h or --help"RST"                      for help");
    712     ret 0;
    713   }
    714   if (argc == 2) {
    715     if (eqG(argv[1], "help") or eqG(argv[1], "--help") or eqG(argv[1], "-h")) goto help;
    716     elif (eqG(argv[1], "list")) {
    717       list();
    718       ret 0;
    719     }
    720     elif (eqG(argv[1], "demo")) {
    721       demo();
    722       ret 0;
    723     }
    724     goto help;
    725   }
    726 
    727   if (argc == 3) {
    728     if (eqG(argv[1], "color")) {
    729       cleanAllocateSmallArray(fontFile);
    730       cleanCharP(p) = expandHome(FONT_DIR"PressStart2P.twidf");
    731       readFileG(fontFile, p);
    732 
    733       twidfont font = init0Var;
    734 
    735       parseTwidFont(fontFile, &font);
    736 
    737       showStringHalfblockNoFullBlock(&font, argv[2]);
    738 
    739       freeTwidFont(&font);
    740       ret 0;
    741     }
    742     goto help;
    743   }
    744 
    745   cleanCharP(fontname) = catS(argv[2], ".twidf");
    746   if (not isPath(fontname)) {
    747     freen(fontname);
    748     cleanCharP(p) = catS(FONT_DIR, argv[2], ".twidf");
    749     fontname      = expandHome(p);
    750     if (not isPath(fontname)) {
    751       logE("Font file not found: %s", argv[2]);
    752       ret 1;
    753     }
    754   }
    755 
    756   cleanAllocateSmallArray(fontFile);
    757   readFileG(fontFile, fontname);
    758 
    759   twidfont font = init0Var;
    760 
    761   parseTwidFont(fontFile, &font);
    762 
    763   if   (not font.pixel)
    764     showStringRaw(&font,  argv[3]);
    765   elif (eqG(argv[1], "-s"))
    766     showString2by3(&font, argv[3]);
    767   elif (eqG(argv[1], "-f"))
    768     showStringQuadrant(&font, argv[3]);
    769   elif (eqG(argv[1], "-F"))
    770     showStringHalfblock(&font, argv[3]);
    771 
    772   freeTwidFont(&font);
    773   ret 0;
    774 
    775   {
    776     cleanAllocateSmallArray(fontFile);
    777     //readFileG(fontFile, "WithheldData.twidf");
    778     //readFileG(fontFile, "Warioland.twidf");
    779     readFileG(fontFile, "PressStart2P.twidf");
    780     // TODO readFileG(fontFile, "hazeltine.twidf");
    781 
    782     twidfont font = init0Var;
    783 
    784     parseTwidFont(fontFile, &font);
    785 
    786     logI("Font height %d", font.height);
    787 
    788     arange(i, font.chars) {
    789       if (font.chars[i].width) {
    790         //showSymbolQuadrant(&font, i);
    791         showRawSymbol(&font, i);
    792       }
    793     }
    794 
    795     /* showRawSymbol(&font, '#'); */
    796     /* showRawSymbol(&font, '$'); */
    797     /* showSymbolHalfBlock(&font, '#'); */
    798     /* showSymbolHalfBlock(&font, '$'); */
    799     /* showSymbolQuadrant(&font, '#'); */
    800     /* showSymbolQuadrant(&font, '$'); */
    801     //showStringQuadrant(&font, "0123456789 abcdefghijklmnopqrstuvwxz ABCDEFGHIJKLMNOPQRSTUVWXZ");
    802     showStringHalfblock(&font, "0123 abcd ABCD");
    803     showStringHalfblockNoFullBlock(&font, "0123 abcd ABCD");
    804     showStringQuadrant(&font, "Press Start");
    805     showStringQuadrant(&font, "> <");
    806 
    807     showStringRaw(&font, "12");
    808 
    809     // demo
    810     cleanSmallArrayP(dir) = readDirG(rtSmallArrayt, ".");
    811 
    812     iter(dir, L) {
    813       castS(l,L);
    814       if (endsWithG(l, ".twidf")) {
    815         logI("%m", l);
    816         cleanAllocateSmallArray(fontFile);
    817         readFileG(fontFile, l);
    818         twidfont font = init0Var;
    819         parseTwidFont(fontFile, &font);
    820         showStringQuadrant(&font, "0123 abcd ABCD");
    821         showStringHalfblock(&font, "0123 abcd ABCD");
    822         freeTwidFont(&font);
    823       }
    824     }
    825 
    826     freeTwidFont(&font);
    827   }
    828 }
    829 // vim: set expandtab ts=2 sw=2: