如何制作自定义 svg 字体字形?

How to make custom svg font glyphs?

我正在尝试为 unicode 盲文范围制作 svg 字体。 我希望黑点是(#fontcolor)中的填充点,非点是圆线。

"⠛" 变成下面的 svg:

<svg width="40" height="80">
    <g
        style="fill-opacity:1;fill:#000000;stroke:#000000;stroke-width:2;stroke-opacity:1"
    >
        <circle id="c0"
            cx="10" cy="10" r="9" />
        <circle id="c1"
            cx="10" cy="30" r="9" />
        <circle id="c2"
            style="fill:none;"
            cx="10" cy="50" r="9" />
        <circle id="c3"
            cx="30" cy="10" r="9" />
        <circle id="c4"
            cx="30" cy="30" r="9" />
        <circle id="c5"
            style="fill:none;"
            cx="30" cy="50" r="9" />
        <circle id="c6"
            style="fill:none;"
            cx="10" cy="70" r="9" />
        <circle id="c7"
            style="fill:none;"
            cx="30" cy="70" r="9" />
    </g>
</svg>

这是我要复制的图像:

如您所知,盲文字形之间的关系是高度父系的。一个盲文字形有 8 个可能的点,每个点就像一个位:从 2800 到 28ff,或 00 到 ff,盲文 glpyhs 似乎明显映射到一个 8 位二进制数。

制作 256 个字形也是一项艰巨的工作。所以我写了一些 C 来自动生成 svg 字形。但是,生成的 svg 字体似乎不正确,因为在使用它时,每个字形都呈现为单个填充点,但我不知道问题出在哪里。这是一个编程错误吗?未能遵循 svg 字体规范?

一个错误是我手动将样式设置为“黑色”。我希望这是字体的 css 颜色,但我不知道如何从 svg 字体中“访问”该“变量”。

编译并 运行 没有特殊标志,将输出通过管道传输到“font.svg”。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

typedef unsigned char u8;

void generateSVG(){

    /* unicode braille

    8 "bits" per glyph.

    pattern where each bit gets placed in the glyph:

    0 3
    1 4
    2 5
    6 7

    */
    const char* prelude = 
    "<svg width=\"100%\" height=\"100%\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">"
    "<defs>"
    "<font id=\"Braille-font\" horiz-adv-x=\"40\">"
    "<font-face"
    "   units-per-em=\"40\""
    "   cap-height=\"80\""
    "   x-height=\"80\""
    "   ascent=\"80\""
    "   descent=\"0\""
    "   bbox=\"0, 0, 40, 80\""
    "   unicode-range=\"U+2800-28ff\""
    "   font-variant = \"normal\""
    ">"
    "<font-face-src>"
    "   <font-face-name name=\"Braille Font\" />"
    "</font-face-src>"
    "</font-face>";

    const char* postlude = "</font></defs></svg>";

    printf("%s\n", prelude);

    const int poslut[8][2] = {
        {10,10},
        {10,30},
        {10,50},
        {30,10},
        {30,30},
        {30,50},
        {10,70},
        {30,70}
    }; // {x,y}[]

    const char* cfmt = "<circle cx=\"%d\" cy=\"%d\" r=\"9\" %s/>";
    const char* gfmt = "<glyph glyph-name=\"uni28%02x\" unicode=\"&#x28%02x;\" horiz-adv-x=\"40\">";

    // [0] = override the fill to "none", [1] = don't override
    const char* fills[2] = {"style=\"fill:none;\" ",""};

    u8 i = 0;
    do {

        char buffer[1024] = {'[=11=]'};
        int pos = sprintf(buffer, gfmt, i,i);

        u8 bits[8] = {
            [0] = i & 0b00000001,
            [1] = i & 0b00000010,
            [2] = i & 0b00000100,
            [3] = i & 0b00001000,
            [4] = i & 0b00010000,
            [5] = i & 0b00100000,
            [6] = i & 0b01000000,
            [7] = i & 0b10000000
        };
        // for some reason the bit shift method (i&(1<<bit)) does not work, so an ugly lut is required

        for (u8 bit = 0; bit < 8; ++bit)
        {
            int x = poslut[bit][0];
            int y = poslut[bit][1];

            //const char* fill = i&(1<<bit) ? fills[1] : fills[0] ;
            //const char* fill = fills[ i&(1<<bit) != 0 ];
            const char* fill = fills[bits[bit] != 0];


            pos += sprintf(&buffer[pos], cfmt,
                                         x, y, fill
            );
        }
        pos += sprintf(&buffer[pos], "</glyph>");

        printf("%s\n", buffer);

        i++;
    } while (i != 0); // 256 mod 256 = 0

    printf("%s\n", postlude);
}

这里是 'filled' 和 'hollow' 圆形路径的示例:

外圈(顺时针):'M cx-or,cy A or,or 1 1 1 cx+or,cy A or,or 1 1 1 cx-or,cy'

内圈(逆时针):'M cx+ir,cy A ir ir 1 1 0 cx-ir,cy A ir,ir 1 1 0 cx+ir,cy'

其中 cx,cy - 中心点坐标,ir - 内半径, - 外半径

实心圆只是外圆,空心圆是内外圆的组合。

<svg width="32" height="32">
  <path d="M 6,12 A 6,6 1 1 1 18,12 A 6,6 1 1 1 6,12"/>
</svg>
  
<svg width="32" height="32">  
  <path d="M 6,12 A 6,6 1 1 1 18,12 A 6,6 1 1 1 6,12 M 16,12 A 4,4 1 1 0 8,12 A 4,4 1 1 0 16,12"/> 
</svg>