termfont

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: