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ڡُ

文本段2abc

第二步处理结果如下:

ڡُ 的字形 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 ) 函数输出的结果,可以看出两者基本一致。