"Fossies" - the Fresh Open Source Software Archive

Member "libcaca-0.99.beta20/tools/makefont.c" (19 Oct 2021, 14893 Bytes) of package /linux/privat/libcaca-0.99.beta20.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "makefont.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.99.beta19_vs_0.99.beta20.

    1 /*
    2  *  makefont    create libcaca font data
    3  *  Copyright © 2006—2021 Sam Hocevar <sam@hocevar.net>
    4  *              All Rights Reserved
    5  *
    6  *  This program is free software. It comes without any warranty, to
    7  *  the extent permitted by applicable law. You can redistribute it
    8  *  and/or modify it under the terms of the Do What the Fuck You Want
    9  *  to Public License, Version 2, as published by Sam Hocevar. See
   10  *  http://www.wtfpl.net/ for more details.
   11  *
   12  * Usage:
   13  *   makefont <prefix> <font> <dpi> <bpp>
   14  */
   15 
   16 #include "config.h"
   17 
   18 #include <stdio.h>
   19 #include <stdlib.h>
   20 #include <stdint.h>
   21 
   22 #if defined HAVE_ARPA_INET_H
   23 #   include <arpa/inet.h>
   24 #elif defined HAVE_NETINET_IN_H
   25 #   include <netinet/in.h>
   26 #endif
   27 
   28 #include <pango/pango.h>
   29 #include <pango/pangoft2.h>
   30 
   31 #include "caca_stubs.h"
   32 #include "caca.h"
   33 
   34 /* Split our big strings into chunks of 480 characters, because it is
   35  * the multiple of 32 directly below 509, which is the maximum allowed
   36  * string size in C89. */
   37 #define STRING_CHUNKS 480
   38 
   39 /* This list is built so that it includes all of ASCII, Latin-1, CP-437,
   40  * and the UTF-8 glyphs necessary for canvas rotation and mirroring. */
   41 static unsigned int const blocklist[] =
   42 {
   43     0x0020, 0x0080, /* Basic latin: A, B, C, a, b, c */
   44 #if 0
   45     0x0080, 0x0100, /* Latin-1 Supplement: Ä, Ç, å, ß */
   46     0x0100, 0x0180, /* Latin Extended-A: Ā č Ō œ */
   47     0x0180, 0x0250, /* Latin Extended-B: Ǝ Ƹ */
   48     0x0250, 0x02b0, /* IPA Extensions: ɐ ɔ ɘ ʌ ʍ */
   49     0x0370, 0x0400, /* Greek and Coptic: Λ α β */
   50     0x0400, 0x0500, /* Cyrillic: И Я */
   51     0x0530, 0x0590, /* Armenian: Ո */
   52     0x1401, 0x1677, /* Unified Canadian Aboriginal Syllabics: ᒐ ᗡ */
   53     0x1d00, 0x1d80, /* Phonetic Extensions: ᴉ ᵷ */
   54     0x2000, 0x2070, /* General Punctuation: ‘’ “” */
   55     0x2100, 0x2150, /* Letterlike Symbols: Ⅎ */
   56     0x2200, 0x2300, /* Mathematical Operators: ∀ √ ∞ ∙ */
   57     0x2300, 0x2400, /* Miscellaneous Technical: ⌐ ⌂ ⌠ ⌡ */
   58     0x2500, 0x2580, /* Box Drawing: ═ ║ ╗ ╔ ╩ */
   59     0x2580, 0x25a0, /* Block Elements: ▛ ▞ ░ ▒ ▓ */
   60     0x25a0, 0x2600, /* Geometric Shapes: ◆ ○ ● */
   61     0x2600, 0x2700, /* Miscellaneous Symbols: ♥ ★ ☭ */
   62     0x3000, 0x3040, /* CJK Symbols and Punctuation: 。「」 */
   63     0x3040, 0x30a0, /* Hiragana: で す */
   64     0x30a0, 0x3100, /* Katakana: ロ ル */
   65     0xff00, 0xfff0, /* Halfwidth and Fullwidth Forms: A, B, C, a, b, c */
   66     0x10400, 0x10450, /* Deseret: 𐐒 𐐋 */
   67 #endif
   68     0, 0
   69 };
   70 
   71 struct glyph
   72 {
   73     uint32_t unicode;
   74     char buf[10];
   75     unsigned int same_as;
   76     unsigned int data_offset;
   77     unsigned int data_width;
   78     unsigned int data_size;
   79 };
   80 
   81 static void fix_glyph(FT_Bitmap *, uint32_t, unsigned int, unsigned int);
   82 static int printf_unicode(struct glyph *);
   83 static int printf_hex(char const *, uint8_t *, int);
   84 static int printf_u32(char const *, uint32_t);
   85 static int printf_u16(char const *, uint16_t);
   86 
   87 /* Counter for written bytes */
   88 static int written = 0;
   89 
   90 int main(int argc, char *argv[])
   91 {
   92     PangoContext *cx;
   93     PangoFontDescription *fd;
   94     PangoFontMap *fm;
   95     PangoLayout *l;
   96     PangoRectangle r;
   97 
   98     FT_Bitmap img;
   99     int stdwidth, fullwidth, height, blocks, glyphs, fullglyphs;
  100     unsigned int n, b, i;
  101     unsigned int stdsize, fullsize, control_size, data_size, current_offset;
  102     uint8_t *glyph_data;
  103     struct glyph *gtab;
  104 
  105     unsigned int bpp, dpi;
  106     char const *prefix, *font;
  107 
  108     if(argc != 5)
  109     {
  110         fprintf(stderr, "%s: wrong argument count\n", argv[0]);
  111         fprintf(stderr, "usage: %s <prefix> <font> <dpi> <bpp>\n", argv[0]);
  112         fprintf(stderr, "eg: %s monospace9 \"Monospace 9\" 96 4\n", argv[0]);
  113         return -1;
  114     }
  115 
  116     prefix = argv[1];
  117     font = argv[2];
  118     dpi = atoi(argv[3]);
  119     bpp = atoi(argv[4]);
  120 
  121     if(dpi == 0 || (bpp != 1 && bpp != 2 && bpp != 4 && bpp != 8))
  122     {
  123         fprintf(stderr, "%s: invalid argument\n", argv[0]);
  124         return -1;
  125     }
  126 
  127     fprintf(stderr, "Font \"%s\", %i dpi, %i bpp\n", font, dpi, bpp);
  128 
  129     /* Initialise Pango */
  130     fm = pango_ft2_font_map_new();
  131     pango_ft2_font_map_set_resolution(PANGO_FT2_FONT_MAP(fm), dpi, dpi);
  132     cx = pango_ft2_font_map_create_context(PANGO_FT2_FONT_MAP(fm));
  133 
  134     l = pango_layout_new(cx);
  135     if(!l)
  136     {
  137         fprintf(stderr, "%s: unable to initialise pango\n", argv[0]);
  138         g_object_unref(cx);
  139         return -1;
  140     }
  141 
  142     fd = pango_font_description_from_string(font);
  143     pango_layout_set_font_description(l, fd);
  144     pango_font_description_free(fd);
  145 
  146     /* Initialise our FreeType2 bitmap */
  147     img.width = 256;
  148     img.pitch = 256;
  149     img.rows = 256;
  150     img.buffer = malloc(256 * 256);
  151     img.num_grays = 256;
  152     img.pixel_mode = ft_pixel_mode_grays;
  153 
  154     /* Test rendering so that we know the glyph width */
  155     pango_layout_set_markup(l, "@", -1);
  156     pango_layout_get_extents(l, NULL, &r);
  157     stdwidth = PANGO_PIXELS(r.width);
  158     fullwidth = stdwidth * 2;
  159     height = PANGO_PIXELS(r.height);
  160     stdsize = ((stdwidth * height) + (8 / bpp) - 1) / (8 / bpp);
  161     fullsize = ((fullwidth * height) + (8 / bpp) - 1) / (8 / bpp);
  162 
  163     /* Compute blocks and glyphs count */
  164     blocks = 0;
  165     glyphs = 0;
  166     fullglyphs = 0;
  167     for(b = 0; blocklist[b + 1]; b += 2)
  168     {
  169         blocks++;
  170         glyphs += blocklist[b + 1] - blocklist[b];
  171         for(i = blocklist[b]; i < blocklist[b + 1]; i++)
  172             if(caca_utf32_is_fullwidth(i))
  173                 fullglyphs++;
  174     }
  175 
  176     control_size = 28 + 12 * blocks + 8 * glyphs;
  177     data_size = stdsize * (glyphs - fullglyphs) + fullsize * fullglyphs;
  178 
  179     gtab = malloc(glyphs * sizeof(struct glyph));
  180     glyph_data = malloc(data_size);
  181 
  182     /* Let's go! */
  183     printf("/* libcaca font file\n");
  184     printf(" * \"%s\": %i dpi, %i bpp, %ix%i/%ix%i glyphs\n",
  185            font, dpi, bpp, stdwidth, height, fullwidth, height);
  186     printf(" * Automatically generated by tools/makefont.c:\n");
  187     printf(" *   tools/makefont %s \"%s\" %i %i\n", prefix, font, dpi, bpp);
  188     printf(" */\n");
  189     printf("\n");
  190 
  191     printf("static size_t const %s_size = %i;\n",
  192            prefix, 4 + control_size + data_size);
  193     printf("static uint8_t const %s_data[%i] =\n",
  194            prefix, 4 + control_size + data_size);
  195     printf("{\n");
  196 
  197     printf("/* file: */\n");
  198     printf("0xCA,0xCA, /* caca_header */\n");
  199     written += 2;
  200     printf("'F','T', /* caca_file_type */\n");
  201     written += 2;
  202     printf("\n");
  203 
  204     printf("/* font_header: */\n");
  205     printf_u32("%s /* control_size */\n", control_size);
  206     printf_u32("%s /* data_size */\n", data_size);
  207     printf_u16("%s /* version */\n", 1);
  208     printf_u16("%s /* blocks */\n", blocks);
  209     printf_u32("%s /* glyphs */\n", glyphs);
  210     printf_u16("%s /* bpp */\n", bpp);
  211     printf_u16("%s /* std width */\n", stdwidth);
  212     printf_u16("%s /* std height */\n", height);
  213     printf_u16("%s /* max width */\n", fullwidth);
  214     printf_u16("%s /* max height */\n", height);
  215     printf_u16("%s /* flags */\n", 1);
  216     printf("\n");
  217 
  218     printf("/* block_info: */\n");
  219     n = 0;
  220     for(b = 0; blocklist[b + 1]; b += 2)
  221     {
  222         printf_u32("%s", blocklist[b]);
  223         printf_u32("%s", blocklist[b + 1]);
  224         printf_u32("%s\n", n);
  225         n += blocklist[b + 1] - blocklist[b];
  226     }
  227     printf("\n");
  228 
  229     /* Render all glyphs, so that we can know their offset */
  230     current_offset = n = 0;
  231     for(b = 0; blocklist[b + 1]; b += 2)
  232     {
  233         for(i = blocklist[b]; i < blocklist[b + 1]; i++)
  234         {
  235             int x, y, bytes, current_width = stdwidth;
  236             unsigned int k, current_size = stdsize;
  237 
  238             if(caca_utf32_is_fullwidth(i))
  239             {
  240                 current_width = fullwidth;
  241                 current_size = fullsize;
  242             }
  243             gtab[n].unicode = i;
  244             bytes = caca_utf32_to_utf8(gtab[n].buf, gtab[n].unicode);
  245             gtab[n].buf[bytes] = '\0';
  246 
  247             /* Render glyph on a bitmap */
  248             pango_layout_set_text(l, gtab[n].buf, -1);
  249             memset(img.buffer, 0, img.pitch * height);
  250             pango_ft2_render_layout(&img, l, 0, 0);
  251 
  252             /* Fix glyphs that we know how to handle better */
  253             fix_glyph(&img, gtab[n].unicode, current_width, height);
  254 
  255             /* Write bitmap as an escaped C string */
  256             memset(glyph_data + current_offset, 0, current_size);
  257             k = 0;
  258             for(y = 0; y < height; y++)
  259             {
  260                 for(x = 0; x < current_width; x++)
  261                 {
  262                     uint8_t pixel = img.buffer[y * img.pitch + x];
  263 
  264                     pixel >>= (8 - bpp);
  265                     glyph_data[current_offset + k / 8]
  266                         |= pixel << (8 - bpp - (k % 8));
  267                     k += bpp;
  268                 }
  269             }
  270 
  271             /* Check whether this is the same glyph as another one. Please
  272              * don't bullshit me about sorting, hashing and stuff like that,
  273              * our data is small enough for this to work. */
  274             for(k = 0; k < n; k++)
  275             {
  276                 if(gtab[k].data_size != current_size)
  277                     continue;
  278 #if 0
  279                 if(!memcmp(glyph_data + gtab[k].data_offset,
  280                            glyph_data + current_offset, current_size))
  281                     break;
  282 #endif
  283             }
  284 
  285             gtab[n].data_offset = current_offset;
  286             gtab[n].data_width = current_width;
  287             gtab[n].data_size = current_size;
  288             gtab[n].same_as = k;
  289 
  290             if(k == n)
  291                 current_offset += current_size;
  292 
  293             n++;
  294         }
  295     }
  296 
  297     printf("/* glyph_info: */\n");
  298     n = 0;
  299     for(b = 0; blocklist[b + 1]; b += 2)
  300     {
  301         for(i = blocklist[b]; i < blocklist[b + 1]; i++)
  302         {
  303             printf_u16("%s", gtab[n].data_width);
  304             printf_u16("%s", height);
  305             printf_u32("%s\n", gtab[gtab[n].same_as].data_offset);
  306             n++;
  307         }
  308     }
  309     printf("\n");
  310 
  311     printf("/* font_data: */\n");
  312     n = 0;
  313     for(b = 0; blocklist[b + 1]; b += 2)
  314     {
  315         for(i = blocklist[b]; i < blocklist[b + 1]; i++)
  316         {
  317             /* Print glyph value in comment */
  318             printf("/* ");
  319             printf_unicode(&gtab[n]);
  320 
  321             if(gtab[n].same_as == n)
  322             {
  323                 char const *lut = " .:nmW@";
  324                 printf("\n");
  325                 for (int y = 0; y < height; ++y)
  326                 {
  327                     for (int x = 0; x < gtab[n].data_width; ++x)
  328                     {
  329                         int val = glyph_data[gtab[n].data_offset + y * gtab[n].data_width + x];
  330                         char ch = lut[val * val * 7 / 256 / 256];
  331                         printf("%c%c", ch, ch);
  332                     }
  333                     printf("\n");
  334                 }
  335                 //printf_hex(" */ %s\n",
  336                 //           glyph_data + gtab[n].data_offset, gtab[n].data_size);
  337             }
  338             else
  339             {
  340                 printf(" is ");
  341                 printf_unicode(&gtab[gtab[n].same_as]);
  342                 printf(" */\n");
  343             }
  344 
  345             n++;
  346         }
  347     }
  348 
  349     printf("};\n");
  350 
  351     free(img.buffer);
  352     free(gtab);
  353     free(glyph_data);
  354     g_object_unref(l);
  355     g_object_unref(cx);
  356     g_object_unref(fm);
  357 
  358     return 0;
  359 }
  360 
  361 /*
  362  * XXX: the following functions are local
  363  */
  364 
  365 static void fix_glyph(FT_Bitmap *i, uint32_t ch,
  366                       unsigned int width, unsigned int height)
  367 {
  368     unsigned int x, y;
  369 
  370     switch(ch)
  371     {
  372     case 0x00002580: /* ▀ */
  373         for(y = 0; y < height; y++)
  374             for(x = 0; x < width; x++)
  375                 i->buffer[x + y * i->pitch] = y < height / 2 ? 0xff : 0x00;
  376         if(height & 1)
  377             for(x = 0; x < width; x++)
  378                 i->buffer[x + (height / 2) * i->pitch] = 0x7f;
  379         break;
  380     case 0x00002584: /* ▄ */
  381         for(y = 0; y < height; y++)
  382             for(x = 0; x < width; x++)
  383                 i->buffer[x + y * i->pitch] = y < height / 2 ? 0x00 : 0xff;
  384         if(height & 1)
  385             for(x = 0; x < width; x++)
  386                 i->buffer[x + (height / 2) * i->pitch] = 0x7f;
  387         break;
  388     case 0x0000258c: /* ▌ */
  389         for(y = 0; y < height; y++)
  390             for(x = 0; x < width; x++)
  391                 i->buffer[x + y * i->pitch] = x < width / 2 ? 0xff : 0x00;
  392         if(width & 1)
  393             for(y = 0; y < height; y++)
  394                 i->buffer[(width / 2) + y * i->pitch] = 0x7f;
  395         break;
  396     case 0x00002590: /* ▐ */
  397         for(y = 0; y < height; y++)
  398             for(x = 0; x < width; x++)
  399                 i->buffer[x + y * i->pitch] = x < width / 2 ? 0x00 : 0xff;
  400         if(width & 1)
  401             for(y = 0; y < height; y++)
  402                 i->buffer[(width / 2) + y * i->pitch] = 0x7f;
  403         break;
  404     case 0x000025a0: /* ■ */
  405         for(y = 0; y < height; y++)
  406             for(x = 0; x < width; x++)
  407                 i->buffer[x + y * i->pitch] =
  408                     (y >= height / 4) && (y < 3 * height / 4) ? 0xff : 0x00;
  409         if(height & 3)
  410             for(x = 0; x < width; x++) /* FIXME: could be more precise */
  411                 i->buffer[x + (height / 4) * i->pitch] =
  412                     i->buffer[x + (3 * height / 4) * i->pitch] = 0x7f;
  413         break;
  414     case 0x00002588: /* █ */
  415         memset(i->buffer, 0xff, height * i->pitch);
  416         break;
  417     case 0x00002593: /* ▓ */
  418         for(y = 0; y < height; y++)
  419             for(x = 0; x < width; x++)
  420                 i->buffer[x + y * i->pitch] =
  421                     ((x + 2 * (y & 1)) & 3) ? 0xff : 0x00;
  422         break;
  423     case 0x00002592: /* ▒ */
  424         for(y = 0; y < height; y++)
  425             for(x = 0; x < width; x++)
  426                 i->buffer[x + y * i->pitch] = ((x + y) & 1) ? 0xff : 0x00;
  427         break;
  428     case 0x00002591: /* ░ */
  429         for(y = 0; y < height; y++)
  430             for(x = 0; x < width; x++)
  431                 i->buffer[x + y * i->pitch] =
  432                     ((x + 2 * (y & 1)) & 3) ? 0x00 : 0xff;
  433         break;
  434     }
  435 }
  436 
  437 static int printf_unicode(struct glyph *g)
  438 {
  439     int wr = 0;
  440 
  441     wr += printf("U+%.04X: \"", g->unicode);
  442 
  443     if(g->unicode < 0x20 || (g->unicode >= 0x7f && g->unicode <= 0xa0))
  444         wr += printf("\\x%.02x\"", g->unicode);
  445     else
  446         wr += printf("%s\"", g->buf);
  447 
  448     return wr;
  449 }
  450 
  451 static int printf_u32(char const *fmt, uint32_t i)
  452 {
  453     uint32_t ni = hton32(i);
  454     return printf_hex(fmt, (uint8_t *)&ni, 4);
  455 }
  456 
  457 static int printf_u16(char const *fmt, uint16_t i)
  458 {
  459     uint16_t ni = hton16(i);
  460     return printf_hex(fmt, (uint8_t *)&ni, 2);
  461 }
  462 
  463 static int printf_hex(char const *fmt, uint8_t *data, int bytes)
  464 {
  465     char buf[BUFSIZ];
  466     char *parser = buf;
  467 
  468     while(bytes--)
  469         parser += sprintf(parser, "%i,", (unsigned int)*data++);
  470     parser[0] = '\0';
  471 
  472     return printf(fmt, buf);
  473 }
  474