Uniscribe 处理文本的简单分析
Uniscribe 实际上可以看成一个工厂,它的原料是字符串文本、Unicode 编码表、各国语言习惯以及字体,产品是字符对应的字形集合、字形的宽度、字形的偏移值。
例:
A..你好吗
处理过程可分为三步:
第一步:纯洁化文本段
根据语言环境将文本段分为属性单一的文本段,属性一般考虑某国语言字符、某国语言标点符号、控制字符、数字等,如A 是拉丁字符,.. 是拉丁标点符号你好吗是中文字符,所以可以分为三部分。
对应ScriptItemize 函数
第二部:字符字形化
对已经纯洁化的文本段进行字形化处理,需要考虑“语境具体化”,即根据上下文决定某些字符的具体字形,此外还要考虑“组合字符”中的一些不能被显示的字符处理(为其指定无法显示的字形)
对应ScriptShape 函数
第三部:字形宽度和偏移计算
此处必须充分考虑“组合字符”,决定寄生字符与宿主字符的位置关系
对应ScriptPlace函数
下面看一个简单的实例:
原料:
字符串 A..你好吗
字体 华文琥珀
产品:
字形 36,17,17,3337,2365,3162
字形宽度 34,22,22,58,58,58
字形偏移 均为0,没有组合字符
我们使用ExtTextOut 来测试结果:
1 CDC* pDC = GetDC();
2 LOGFONT lf;
3 memset(&lf, 0, sizeof(LOGFONT));
4 ::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf);
5 lf.lfHeight = 60;
6 _tcscpy_s(lf.lfFaceName, _T("华文琥珀"));
7
8 CFont font;
9 font.CreateFontIndirect( &lf );
10 CFont* pOldFont = pDC->SelectObject( &font );
11 TCHAR array[] = {36,17,17,3337,2365,3162};
12 ExtTextOut( pDC->GetSafeHdc(), 0, 0, ETO_GLYPH_INDEX, NULL, array, 6, NULL );
13 pDC->SelectObject( pOldFont );
14 font.DeleteObject();
输出结果是
此结果与直接使用
ExtTextOut( pDC->GetSafeHdc(), 0, 0, ETO_GLYPH_INDEX, NULL, TEXT("A..你好吗"), 6, NULL ) 基本一致。
下面来个复杂的例子:
ڡُabc
字体选用Tahoma
这个字符串包含了组合字符,RTL 文本,够复杂了吧,现在分步处理,
第一步处理结果如下:
文本段1:ڡُ
文本段2:abc
第二步处理结果如下:
ڡُ 的字形 757,806
因为是RTL 文本,所以757 是后一个字符的字形,806 是前一个字符的字形
abc 的字形是68,69,70
第三部处理结果如下:
757 字形宽度为0 偏移为x = 8 y = -10
806 字形宽度为44 偏移为0
68 字形宽度为26 偏移为0
69 字形宽度为28 偏移为0
70 字形宽度为23 偏移为0
使用ExtTextOut 测试代码如下:
print?
CDC* pDC = GetDC();
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf);
lf.lfHeight = 60;
_tcscpy_s(lf.lfFaceName, _T("Tahoma"));
CFont font;
font.CreateFontIndirect( &lf );
CFont* pOldFont = pDC->SelectObject( &font );
TCHAR array[] = {757,806,68,69,70};
int iWidth[] = { 0, 44, 26, 28, 23 };
struct OFFSET
{
int x;
int y;
};
OFFSET offsets[] =
{
8, -10,
0,0,
0,0,
0,0,
0,0,
};
pDC->SetBkMode( TRANSPARENT );
// 先处理前两个字形,因为它们是文本属性相同的
int iStartX = 0;
int iStartY = 50;
// 第一个字形,但却是第二个字符,根据偏移值输出字形
ExtTextOut( pDC->GetSafeHdc(), iStartX + offsets[0].x, iStartY - offsets[0].y, ETO_GLYPH_INDEX, NULL, array, 1, NULL );
// 第二个字形,第一个字形宽度为0,无偏移
ExtTextOut( pDC->GetSafeHdc(), iStartX + iWidth[0], iStartY, ETO_GLYPH_INDEX, NULL, array + 1, 1, NULL );
// 处理后三个字形,因为偏移值均为0,所以一次性处理
ExtTextOut( pDC->GetSafeHdc(), iStartX + iWidth[0] + iWidth[1], iStartY, ETO_GLYPH_INDEX, NULL, array + 2, 3, NULL );
ExtTextOut( pDC->GetSafeHdc(), iStartX, 100, 0, NULL, TEXT( "ڡُabc" ), 5, NULL );
pDC->SelectObject( pOldFont );
font.DeleteObject();
显示结果如下:
上面一个是测试代码的显示结果,下面一个是使用ExtTextOut( pDC->GetSafeHdc(), iStartX, 100, 0, NULL, TEXT( "ڡُabc" ), 5, NULL ) 函数输出的结果,可以看出两者基本一致。