我目前正在为嵌入式显示器设计字体引擎。基本问题如下:
我需要采用动态生成的文本字符串,在UTF-8表中查找该字符串中的值,然后使用该表指向所有支持字符的压缩位图数组。完成后,我调用一个bitcopy例程,将数据从位图数组移动到显示器。
我不支持完整的UTF-8字符集,因为我使用非常有限的系统资源(32K ROM,8K RAM),但希望能够稍后添加所需的字形以用于本地化目的。所有开发都在C和汇编中完成。
字形大小最大为16位宽,16位高。我们可能需要支持整个基本多语言平面(3个字节),因为我们的一些大客户在亚洲。但是,我们不会将整个表格包含在任何特定的本地化中。
我的问题是:
添加此UTF-8支持和关联表的最佳方法是什么?
答案 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中。