"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.

    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