如何向嵌入式项目添加UTF-8支持和相关的字体表?

时间:2009-03-19 17:35:54

标签: c utf-8 embedded

我目前正在为嵌入式显示器设计字体引擎。基本问题如下:

我需要采用动态生成的文本字符串,在UTF-8表中查找该字符串中的值,然后使用该表指向所有支持字符的压缩位图数组。完成后,我调用一个bitcopy例程,将数据从位图数组移动到显示器。

我不支持完整的UTF-8字符集,因为我使用非常有限的系统资源(32K ROM,8K RAM),但希望能够稍后添加所需的字形以用于本地化目的。所有开发都在C和汇编中完成。

字形大小最大为16位宽,16位高。我们可能需要支持整个基本多语言平面(3个字节),因为我们的一些大客户在亚洲。但是,我们不会将整个表格包含在任何特定的本地化中。

我的问题是:
添加此UTF-8支持和关联表的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

下面的解决方案假设Unicode空间的低16位对您来说足够了。如果你的位图表有,比如U + 0020到U + 007E,位置0x00到0x5E,U + 00A0到U + 00FF,位置0x5F到0xBE,U + 1200到U + 1241,位于0xBF到0xFF,你可以这样做下面的代码(未经过测试,甚至未经过编译测试)。

bitmapmap包含一系列值。第一对中的第一个值是索引0处的位图表示的Unicode代码点。假设位图表包含一系列直接相邻的Unicode代码点。所以第二个值表示这个系列有多长。

while循环的第一部分迭代UTF-8输入并在ucs2char中构建Unicode代码点。找到完整字符后,第二部分将在bitmapmap中提到的某个范围内搜索该字符。如果找到合适的位图索引,则将其添加到索引中。没有位图的字符会被静默删除。

该函数返回找到的位图索引数。

这种做法在unicode->位图表方面应该具有记忆效率,相当快速且相当灵活。

// Code below assumes C99, but is about three cut-and-pastes from C89
// Assuming an unsigned short is 16-bit

unsigned short bitmapmap[]={0x0020, 0x005E,
                            0x00A0, 0x0060,
                            0x1200, 0x0041,
                            0x0000};

int utf8_to_bitmap_indexes(unsigned char *utf8, unsigned short *indexes)
{
    int bitmapsfound=0;
    int utf8numchars;
    unsigned char c;
    unsigned short ucs2char;
    while (*utf8)
    {
        c=*utf8;
        if (c>=0xc0)
        {
            utf8numchars=0;
            while (c&0x80)
            {
                utf8numchars++;
                c<<=1;
            }
            c>>=utf8numchars;
            ucs2char=0;
        }
        else if (utf8numchars && c<0x80)
        {
            // This is invalid UTF-8.  Do our best.
            utf8numchars=0;
        }

        if (utf8numchars)
        {
            c&=0x3f;
            ucs2char<<=6;
            ucs2char+=c;
            utf8numchars--;
            if (utf8numchars)
                continue; // Our work here is done - no char yet
        }
        else
            ucs2char=c;

        // At this point, we have a complete UCS-2 char in ucs2char

        unsigned short bmpsearch=0;
        unsigned short bmpix=0;
        while (bitmapmap[bmpsearch])
        {
            if (ucs2char>=bitmapmap[bmpsearch] && ucs2char<=bitmapmap[bmpsearch]+bitmapmap[bmpsearch+1])
            {
                *indexes++ = bmpix+(ucs2char-bitmapmap[bmpsearch]);
                bitmapsfound++;
                break;
            }

            bmpix+=bitmapmap[bmpsearch+1];
            bmpsearch+=2;
        }
    }
    return bitmapsfound;
}

编辑:你提到你需要的不仅仅是低16位。 s / unsigned short / unsigned int /; s / ucs2char / codepoint /;在上面的代码中,然后它可以完成整个Unicode空间。

答案 1 :(得分:0)

您没有指定字符的大小,或者字符集的大小是多少,因此很难估计大小要求。

我会将位图存储为直接数组格式,具体取决于字符的大小,它可以相当高效地存储而无需打包/解包元素。

例如,如果我们采用带有8x6字符的36个字符的字母表,那么阵列需要216个字节的存储空间。 (6个字节/字符* 36 - 每个字节都是字符的垂直切片。)

对于解析,只需在表格中进行偏移即可 旧的(char - 'A')和(char - '0')技巧做得很好。

另一个问题是存储位图数组的位置。 在ROM中是明显的答案,但是如果你需要支持其他字形,它可能需要重新编程,如果这是一个问题你没有指定。

如果字形必须动态编程,那么你没有选择,只能把它放在RAM中。