天天看點

【物聯網智能網關-08】TinyGUI和WPF漢字顯示技術比較

TinyGUI是我在2010上半年的時候,基于.NET Micro Framework系統開發的一個輕量級圖形庫,雖然TinyGUI運作需要的資源少,運作快,但是不支援漢字顯示(如需顯示漢字還是必須借助WPF本身的功能,這顯然背離了TinyGUI占用資源少的設計初衷了)。另外物聯網組态系統YFHMI,考慮到性能和資源問題,也是要選擇TinyGUI庫的,而漢字顯示功能又必不可少,這一切都促使了TinyGUI支援漢字顯示功能的實作。

一個GB2312字庫大概含7、8千漢字字元,最常用的16*16點陣的這種字庫,大概需要300K的RAM空間。如果同時支援幾種字型,RAM的需求量會非常大,這對小型嵌入式系統來說是非常不可取的,

最初,我很自然的打算就是讓TinyGUI借助Tinyfnt字庫,進行漢字顯示。沒有想到事隔5年重新又深入研究tinyfnt字型結構,方明白tinyfnt的字型點陣内容原來就是一個單色大位圖,并且每個字元的寬度是不确定的,在位圖中存放的位置是緊湊格式,你很難根據一個簡單的算法,計算出第n個字元是位圖上的那一個區域。此外WPF的實作相關代碼太多和瑣碎,你難以從現有的代碼中進行提取和剝離,換句話說,你想用TinyGUI顯示漢字,TinyCLR還得需要內建WPF絕大數代碼。

不過很不幸的是,UCDOS下的漢字庫是用區位碼進行定位的,而.NET Micro Framework上的應用程式傳入的字元串是UTF8編碼的(底層C++代碼需要自行對UTF8進行解碼為Unicode代碼),而區位碼和Unicode編碼是沒有相關性的,沒有一個簡單統一的公式,進行二者的換算,如果非要進行轉換,那隻有查表這一個途徑了,這将大大增加對RAM的需求量。另外UCDOS下的漢字庫本身隻含漢字資訊,ASCII相關字元點陣資訊,還需要另外的字庫。

這裡補充說明一下:在C++開發層面,ARM編輯器對字元串有兩種編碼格式,一種就是内碼(針對漢字來說高低位元組分别減去0xA0,就是區位碼了),另外一種就是Unicode編碼。比如如下的代碼:

char *s1="abc葉帆科技";

wchar_t *s2=L"abc葉帆科技";

BYTE *p1=(BYTE *)s1,*p2=(BYTE *)s2;

for(int i=0;i<11;i++)

{

   debug_printf("%02X",*p1++);

}

debug_printf("\r\n");

for(int i=0;i<14;i++)

   debug_printf("%02X",*p2++);

其輸出資訊為:

目前大部分嵌入式系統為了實作簡單,都是基于内碼進行漢字顯示的,這就有一個問題,産品如需支援多語言環境,比如同時顯示繁體和簡體就很實作。但是采用Unicode編碼的字元集,就沒有這類問題。

是以我最終決定還是自己做一個支援Unicode編碼的點陣字庫生成程式,生成的字庫不僅支援漢字,也支援ASCII,且ASCII字元的寬度僅是漢字的一半,這樣就非常有利于文字顯示排版。而且和.NET Micro Framework的Tinyfnt字庫一樣,使用者可以自定義字庫的内容(這樣如果需要顯示的漢字不多,字庫就會很小)。

另外考慮到UCDOS字庫專門為點陣字庫而做,其顯示效果要比我們直接從矢量字庫轉換的點陣字庫要漂亮的多,是以程式又添加了一個功能,如果字型名稱選擇了宋體、黑體、楷體和仿宋則會自動出現一個UCDOS選項,勾選這個選項,則點陣資訊直接從UCDOS字庫中提取。

下面就從字庫大小、顯示效果、加載方式和顯示效率等四個方面和WPF漢字顯示進行比較。

字元集:GB2312 + ASCII,字元數:7587

字庫點陣

Tinyfnt實際大小

Tinyfnt(修正)

YFTF

備注

12*12

12*10:190k

228k

207k

16*16

16*14:283k

323k

308k

宋體

24*24

24*20:523k

627k

562k

注:(1)、windows字型中,所謂的字型大小的機關不是像素(px),而是點(pt):1px=3/4pt。比如12像素大小的字型,其實和9号字型相同。

(2)、windows字型轉換為tinyfnt字型的時候,發現很難轉換成正方形字型,比如9号字型轉換為12像素的字型的時候,無論怎麼調整寬度數,好像很難調整到12*12,預設的字型平均寬度是10,是以比較字型庫大小的時候,才會出現一個修正大小的項。

從上表可以看出,如果點陣大小完全相同,tinyfnt字型庫的大小是大于yftf字型庫的大小的。原因是tinyfnt字型庫不僅包含unicode編碼和字型點陣資訊,還包括了每一個字的左右偏移資訊(因為tinyfnt字庫,字型可以不等寬),是以理應比yftf字型庫要大一些。

(從上圖可以看出 tinyfnt的字型存儲的比較緊湊)。

為了便于比較明顯的比較出點陣字型效果差異,我們選擇24*24的點陣字庫進行比較,也包含了UCDOS的HZK24。

從比較的結果看,顯然ucdos漢字庫下提供字型更為漂亮(畢竟是專門為點陣字庫而設計)。Yftf字庫生成工具可以直接借用ucdos的點陣資料(生成的時候,記得勾選ucdos選項即可)。

(1)、WPF标準漢字顯示程式如下:

    dc.DrawText("葉帆工作室[YFSoft]", Resources.GetFont(Resources.FontResources.z_12),c, 5, 25);

    dc.DrawText("葉帆工作室[YFSoft]", Resources.GetFont(Resources.FontResources.MS_16),c, 5, 45);

    dc.DrawText("葉帆工作室[YFSoft]", Resources.GetFont(Resources.FontResources.l_24),c, 5, 65);

從以上代碼可以看出,WPF的字型檔案必須放在資源檔案中,如果你用了一個16點陣的全字庫,你的pe檔案就會非常大,并且每次調試你都需要重新部署到裝置中去,比較耗費時間。

(2)、TinyGUI字型庫加載方式有兩種,一種和WPF一樣,把字型庫檔案放到資源檔案中(字型比較少的字型庫,比較适合放在資源檔案中),另一種就是指定字型庫在NandFlash中的位址和大小,這種方式隻要部署一次就OK了,比較适合全字庫方式。

第一種方式相關的代碼如下:

UInt32 font24= Graphics.LoadFont(Resources.GetBytes(Resources.BinaryResources.Song24yf));

    Graphics.DrawString(10,10, "葉帆科技ABC", Color.Red,font24);

第二種方式的相關代碼如下:

    UInt32song12 = Graphics.LoadFont(0x01480000,0x3397C);

    UInt32song16 = Graphics.LoadFont(0x01480000 +0x3397C, 0x4CE40);

    UInt32song24 = Graphics.LoadFont(0x01480000 +0x807BC, 0x8C76C);

    Graphics.DrawString(10,60, "葉帆科技ABC", Color.Green,song12);

    Graphics.DrawString(10,80, "葉帆科技ABC", Color.Blue,song16);

    Graphics.DrawString(10,110, "葉帆科技ABC", Color.White,song24);

不過在運作該代碼之前,需要用YFAccessFlash工具把相關字型部署到【UserData】NandFlash區,如下圖所示:

我們進行兩種方式的比較,一種是小字庫字型顯示的速度比較,另一種是全字庫字型顯示的速度比較。

相關測試代碼如下:

Graphics.Clear(Color.Black);

    UInt32font16yf = Graphics.LoadFont(Resources.GetBytes(Resources.BinaryResources.Song16yf));

    Fontfont16mf = Resources.GetFont(Resources.FontResources.song16mf);

    Microsoft.SPOT.Presentation.Media.Color c = Microsoft.SPOT.Presentation.Media.Color.White;

    Bitmapbmp = new Bitmap(320,240);

    DateTimet = DateTime.Now;

    for (int i = 0; i < 1000; i++)

    {

        bmp.DrawText("葉帆科技ABC", font16mf, c, 10, 10);

        bmp.Flush(10, 10, 96, 16);

    }

    TimeSpants = DateTime.Now - t;

    Debug.Print("time=" + (ts.Seconds * 1000 +ts.Milliseconds).ToString()+"ms");

    t = DateTime.Now;

        Graphics.DrawString(10,30, "葉帆科技ABC", Color.Red,font16yf);

    ts = DateTime.Now- t;

    Debug.Print("time=" + (ts.Seconds * 1000 +ts.Milliseconds).ToString() + "ms");

    顯示性能比較表:

類型

精簡字庫

全字庫(GB2312)

WPF

1886ms

1910ms

僅重新整理字型區

TinyGUI

880ms

904ms

直接操作顯存

精簡字庫:1886/880 = 2.14

全字庫:1910/904 = 2.11

從上表可以很清楚的看出,TinyGUI顯示漢字的性能是WPF方式的兩倍以上。

(1)、使用YFTinyFont制作yftf字庫檔案

(2)、把字庫寫入NandFlash 【UserData】區或添加到資源中

(3)、程式設計顯示漢字

     UInt32 hwcy48 = Graphics.LoadFont(Resources.GetBytes(Resources.BinaryResources.hwcy48));

     Graphics.DrawString(10, 80, "葉帆科技ABC", Color.White,hwcy48);

     UInt32 hwhp48 = Graphics.LoadFont(Resources.GetBytes(Resources.BinaryResources.hwhp48));

     Graphics.DrawString(10, 132, "葉帆科技ABC", Color.White,hwhp48);

     UInt32fzst48 = Graphics.LoadFont(Resources.GetBytes(Resources.BinaryResources.fzst48));

     Graphics.DrawString(10, 184, "葉帆科技ABC", Color.White,fzst48);

顯示效果圖如下:

除了為TinyGUI增加了直接顯示漢字的功能外,還添加了觸摸屏事件的支援,下一篇博文将介紹TinyGUI觸摸屏功能的相關内容,敬請期待。

 ---------------------------------------------------------------   

<a href="http://weibo.com/1804832611?s=6uyXnP"></a>

繼續閱讀