摘要:MiniGUI是典型的圖形用戶界面系統,它采用面向對象的技術實現多字體和多字符集的支持。MiniGUI針對字體和字符集定義了一系列抽象接口,如果要增加對某種字體或某種字符集的支持,只需實現該字體類型和該字符集的接口即可。該文重點講述了對Unicode字符集和TrueType字體的支持和實現,并提供了Unicode編碼方式的文本處理和顯示的API。
關鍵詞:MiniGUI;TrueType字體;Unicode;字符集
中圖分類號:TP391文獻標識碼:A文章編號:1009-3044(2010)03-738-04
Implement of TrueType Font Based on Unicode encoding
ZHAO Li, CAI Xue-mei
(College of Electroning Engineering, Chongqing University of Posts and Telecommunications, Chongqing 400065, China)
Abstract: MiniGUI is a typical Graphic User Interface System.It achieves multi-font and multi-character set support by adopting the techniques of object-oriented. It defines a series of abstract interface for fonts and character sets,the support of a certain font or a character set is increased by achieving the interfaces of the font type and the character set.The paper describes the support and implement for Unicode character set and TrueType font, and it provides the application program interface of the text process and display in Unicode encoding ways.
Key words: MiniGUI; truetype; unicode; character set
MiniGUI 是一個跨操作系統的、面向嵌入式系統的輕量級圖形用戶界面支持系統。它主要在Linux控制臺上運行,是基于SVGALib和LinuxThread庫的多窗口圖形用戶界面支持系統。它采用了類Win32的API接口,實現了簡化的類Windows 98風格的圖形用戶界面。自1999年初遵循GPL條款發布第一個版本以來,MiniGUI已廣泛應用于手持信息終端、機頂盒、工業控制系統及工業儀表、便攜式多媒體播放機、查詢終端等產品和領域。而且MiniGUI2.0為基于嵌入式Linux的高端嵌入式設備提供了完整的多進程支持,從而將MiniGUI從中端市場帶到了高端市場[3]。
MiniGUI采用了面向對象的技術實現了圖形抽象層(GAL)、輸入抽象層(IAL)以及多字體和多字符集的支持。GAL和IAL大大提高了 MiniGUI 的可移植性,并將底層圖形設備和上層接口分離開來。MiniGUI采用邏輯字體實現多字體和多字符集處理。這一技術成功應用了面向對象技術,通過單一的邏輯接口,可以實現對各種字符集以及各種字體的支持[4]。
1 MiniGUI中TrueType字體的實現
1.1 TrueType字體簡介
TrueType是Apple公司和 Microsoft公司合作開發的頁面描述語言(Page Description Language,PDL)TrueImage中的字形描述部分。TrueType字體(簡稱 TTF)采用直線和二次Bezier曲線來描述字符的輪廓,結合了光柵技術和矢量技術的優點,克服了以往所有點陣字體、矢量字體和向量輪廓字體的缺點,字體可以任意放大、縮小、旋轉和變形而不會影響輸出質量,提供了真正的設備無關性。二次Bezier曲線既能保證輪廓曲線的光滑性,又有利于提高字形還原速度。另外,TrueType所特有的豐富的指令集,不僅彌補了TTF的二次曲線描述輪廓的不足,而且增強了TTF字形描述的靈活性。若要提高字體的質量,不僅可以通過數據信息來實現,而且可通過增加指令來進行。Microsoft公司從Windows 3.1開始就采用TrueType字體技術。隨著Windows的流行,TrueType已經成為事實上的字形描述標準之一[5]。
1.2 TrueType字體的分析及實現
1.2.1 TrueType字體的數據結構
本文采用FreeType這個中間件來實現TrueType字體支持。在MiniGUI設備字體定義中,有一個data字段可用來保存設備字體相關的數據結構。對TrueType字體來講,我們使用 TTFGLYPHINFO和TTFINSTANCEINFO兩個數據結構來存儲TrueType字體的文字輪廓信息和實例信息。
typedef struct tagTTFGLYPHINFO
{
TT_Face face;
TT_Glyphglyph;
TT_UShort last_glyph_index;
TT_CharMapchar_map;
TT_Ushort first_char;
TT_Ushort last_char;
BOOLcan_kern;
TT_Kerningdirectory;
BOOLvalid;
}TTFGLYPHINFO, *PTTFGLYPHINFO;
typedef struct tagTTFINSTANCEINFO {
PTTFGLYPHINFO ttf_glyph_info;
TT_Instance instance;
int rotation;
TT_Matrix matrix;
int max_width;
int ave_width;
int height;
int ascent;
int descent;
unsigned short* widths;
short cur_glyph_code;
TT_Outlinecur_outline;
TT_Poscur_xmin, cur_ymin;
TT_F26Dot6cur_width, cur_height;
TT_Poscur_advance;
short last_glyph_code;
short last_pen_pos;
}TTFINSTANCEINFO,*PTTFINSTANCEINFO;
如前面所說,TTFGLYPHINFO和TTFINSTANCEINFO數據結構來存儲TrueType的圖元信息和實例信息。其中TTFGLYPHINFO中的成員valid是用來判斷該設備字體是否初始化完畢。
1.2.2 TrueType字體的字體操作集freetype_font_ops
MiniGUI 中的設備字體操作集針對每種設備字體類型而定義,包括對這種設備字體的各種操作函數。TrueType字體的字體操作集freetype_font_ops的結構成員及功能如表1所示。
1.2.3 InitFreeTypeFont和TermFreeType Fonts函數
這兩個函數負責整個TrueType字體的初始化和終結。
InitFreeTypeFonts的主要任務是:初始化TTF字庫,并向系統注冊用來處理TrueType字體的字體操作集freetype_font_ops。
TermFreeTypeFonts則是注銷TrueType字體,關閉TTF字庫。
1.2.4向配置文件MiniGUI.cfg添加TrueType字體支持
MiniGUI在初始化時,要讀取MiniGUI.cfg中的字體定義并裝載指定字體文件,裝載后的字體在MiniGUI內部稱為“設備字體”。設備字體定義了這種字體的樣式名、風格、大小以及它所支持的字符集。MiniGUI在創建邏輯字體時,要根據已裝載的設備字體,以及應用程序指定的字體類型、樣式名、大小、字符集等信息尋找合適的設備字體來顯示文本[1]。
在MiniGUI.cfg文件中的systemfont段添加下面代碼:
font4=ttf-sic-rrncnn-*-12-ISO8859-1
font5=ttf-sic-rrncnn-*-16-ISO8859-1
2 MiniGUI中Unicode字符集UTF-16LE編碼方式的實現
MiniGUI對多字符集的支持通過邏輯字體接口來實現。應用程序在顯示文本時,通常要建立邏輯字體,并指定該字體使用的字符集編碼名稱。在創建邏輯字體之后,應用程序就可以使用該邏輯字體顯示文本或者分析文本結構。
Unicode可以用來表示所有語言的字符,而且是定長雙字節(也有四字節的)編碼,包括英文字母在內。所以可以說它是不兼容iso8859-1編碼的,也不兼容任何編碼。它具有多種編碼方式,常見的有:UTF-8,UTF-16,UTF-32。而UTF-16分為UTF-16LE和UTF-16BE,本文采用UTF-16LE編碼方式進行文本顯示和輸出。
常用的文本輸出函數有Text和DrawText等,其中只有DrawText函數不支持UTF-16編碼方式的文本輸出。本文將提供支持Unicode字符集UTF-16LE編碼的DrawText函數[1]。
2.1 DrawText函數相關源代碼導讀
要使DrawText函數支持UTF-16LE編碼,需更改libminigui-1.6.10/src/newgdi目錄下的Text.c文件的部分代碼,改寫方法如下:
1)Text.c 的523行char_len = 1改為char_len = is_utf16_logfont(pdc)?2:1。
2)Text.c 的592行if (is_utf16_logfont (pdc)) return -1注釋掉。
3)Text.c 的536行(*nChar) ++下一行添加if(is_utf16_logfont(pdc))(*nChar) ++。
4)Text.c 的542行char_len = 1改為char_len = is_utf16_logfont(pdc)?2:1。
以上修改的原因是:UTF-16LE編碼是采用兩字節表示字符,包括控制字符。以上修改確保了控制字符采用兩字節輸出。
2.2 文本轉換接口函數MBS2WCSEx
MiniGUI通過MB2WCEx和MBS2WCSEx這兩個接口函數實現多個字符集/編碼(如GB2312、ISO8859、UTF-8、GBK、BIG5等)和UNICODE內碼相互轉換功能,前者一次只轉換一個字符,后者一次可轉換多個字符,因此本文采用MBS2WCSEx函數進行文本轉換[1]。
MBS2WCSEx函數原型如下:int GUIAPI MBS2WCSEx (PLOGFONT log_font, void* dest, BOOL wc32, const unsigned char* mstr, int mstr_len, int n, int* conved_mstr_len);
參數說明:
log_font:邏輯字體
dest:用于存放已轉換的寬字符串的緩沖區
wc32:判斷這個unicode字符是32位還是16位,TRUE表示是32位的,FALSE表示是16位的
mstr:多字節字符串
mstr_len:多字節字符串的長度
n:緩沖區的長度
conved_mstr_len:已正確轉換的寬字符串長度的返回指針,一般為NULL
2.3 對TextOut函數和DrawText函數進行外部封裝
為了方便對支持Unicode字符集UTF-16LE編碼方式的文本輸出,以下是TextOut函數和DrawText函數的封裝的部分代碼。
2.3.1 自定義枚舉類型數據結構如下:
typedef enum {
FONT_UNICODE_DEFAULT = 0,
FONT_UNICODE_SIZE_12,
FONT_UNICODE_SIZE_16,
FONT_UNICODE_SIZE_24,
FONT_UNICODE_MAX
}FONT_UNICODE;
typedef enum {
FONT_TEXT_DEFAULT = 0,
FONT_TEXT_ISO8859_1,
FONT_TEXT_UNICODE,
FONT_TEXT_MAX
}FONT_TEXT;
2.3.2 創建支持Unicode字符集UTF-16LE編碼方式的不同字體大小的TrueType字體
FontUnicode[FONT_UNICODE_SIZE_12] = CreateLogFont (\"ttf\", \"sic\", FONT_CHARSET_UTF16LE, FONT_WEIGHT_REGULAR, FONT_SLANT_ROMAN, FONT_SETWIDTH_NORMAL,FONT_SPACING_CHARCELL, FONT_UNDERLINE_NONE, FONT_STRUCKOUT_NONE, 12, 0);
FontUnicode[FONT_UNICODE_SIZE_16] = CreateLogFont (\"ttf\", \"sic\", FONT_CHARSET_UTF16LE, FONT_WEIGHT_REGULAR, FONT_SLANT_ROMAN, FONT_SETWIDTH_NORMAL,FONT_SPACING_CHARCELL, FONT_UNDERLINE_NONE, FONT_STRUCKOUT_NONE, 16, 0);
FontUnicode[FONT_UNICODE_DEFAULT] = NULL;
2.3.3 TextOut函數和DrawText外部封裝接口
int TextOutUnicode (HDC hdc, int x, int y, const char* spText, FONT_UNICODE newFontIndex,FONT_TEXT originalChaset )
int DrawTextUnicode (HDC hdc, const char* pText, int nCount, RECT* pRect, UINT nFormat,FONT_UNICODE newFontIndex, FONT_TEXT originalChaset )
2.4 向配置文件MiniGUI.cfg中添加Unicode字符集UTF-16LE編碼方式的TrueType字體支持
將從Windows下提取的kaiti.ttf字體文件添加在系統的usr/local/lib/minigui/res/font目錄下,并將MiniGUI.cfg文件中的truetypefont段的代碼改為下面的代碼:
[truetypefonts]
font_number=3
name0=ttf-arial-rrncnn-0-0-ISO8859-1,UTF-16LE
fontfile0=/usr/local/lib/minigui/res/font/arial.ttf
name1=ttf-times-rrncnn-0-0-ISO8859-1,UTF-16LE
fontfile1=/usr/local/lib/minigui/res/font/times.ttf
name2=ttf-kaiti-rrncnn-0-0-ISO8859-1,UTF-16LE
fontfile2=/usr/local/lib/minigui/res/font/kaiti.ttf
3 結束語
通過對TTF字體的技術原理的概述,分析了MiniGUI中TrueType字體的數據結構、字體操作集、字體初始化和字體終結函數,
從而實現了對TrueType字體的支持。
通過對MiniGUI中的Text.c源文件進行分析、導讀、修改實現了DrawText函數對UTF-16LE編碼方式的支持。
通過對文本轉換函數MBS2WCSEx的分析和應用,實現了多字符集/編碼向Unicode內碼的轉換,進而實現了對支持Unicode字符集的文本輸出。
最后,根據上述方法在Ubuntu版本Linux系統上實現了對Unicode字符集UTF-16LE編碼方式的TrueType字體的文本輸出和顯示。
參考文獻:
[1] 魏永明.MiniGUI編程指南[EB/OL].http://www.minigui.com/fileadmin/download/MINIGUI-PROG-GUIDE-V2.0-4C.pdf.
[2] 魏永明.MiniGUI用戶手冊[EB/OL].http://www.minigui.com/fileadmin/download/MINIGUI-USER-MANUAL-V2.0-4C.pdf.
[3] 魏永明.MiniGUI技術白皮書[EB/OL].http://www.minigui.com/fileadmin/download/MiniGUITechWhitePaper-2.0-4C.pdf.2008,10.
[4] 魏永明.MiniGUI體系結構之三:邏輯字體以及多字體和多字符集實現[EB/OL].http://www.ibm.com/developerworks/cn/linux/embed/minigui/minigui-7/index.html.
[5] 吳海輝,樊慶林,王虎.TrueType字體技術的研究分析與應用[J].電腦知識與技術,2007.