|
1、在UCGUI中有兩種類型字體, 一種是等寬字體(Monospaced Font),即字體當(dāng)中所有字都是同一寬度,它在UCGUI中的相應(yīng)結(jié)構(gòu)體是GUI_FONT_MONO, 一種是均衡字體(Proportional font), 這種字體中的字都有自己獨(dú)立的寬度, 字體內(nèi)的每個(gè)字都可以有不同寬度, 它在UCGUI中的相應(yīng)結(jié)構(gòu)體是GUI_FONT_PROP, 對(duì)于等寬字體, 一般都是將所有字的點(diǎn)陣存放在一個(gè)數(shù)組中, 因?yàn)槊總€(gè)字都寬度相同. 對(duì)于均衡字體, 則要單獨(dú)用數(shù)組來(lái)定義每個(gè)字符的點(diǎn)陣, 然后將每一個(gè)字符的寬高及點(diǎn)陣存為一個(gè)數(shù)組即字符信息(ucgui中對(duì)應(yīng)結(jié)體為GUI_CHARINFO), 所有字符信息再存到一個(gè)數(shù)組當(dāng)即稱為字符集, 它包含每個(gè)字的字符信息(點(diǎn)陣高寬及一行占幾個(gè)字節(jié)), 所謂一行占幾個(gè)字節(jié), 是指這個(gè)字體的點(diǎn)陣每一行有多少個(gè)字節(jié), 它與寬度高度單位不同, 寬度高度的單位是象素?cái)?shù). 2.另外特別指出的是, 在等寬字體中不僅所有字符寬度相同,高寬也是相等的; 對(duì)于均衡字體, 不僅可以寬度不同, 高度也可以不同, 每一行有多少個(gè)字節(jié)自然也不同, 在均衡字體中每一個(gè)字符都單獨(dú)定義之后才組成字體的字符集. 3.字符集的問(wèn)題, 在UCGUI中每種字體含的字符集不同, 這個(gè)可以參看UCGUI手冊(cè)中的"Standard Font"一章,這一章中對(duì)于字符集有如下描述: ASCII: Only ASCII characters 0x20-0x7E (0x 1: ASCII characters and European extensions 0xA0 - 0xFF.[除0x20-0x7E這個(gè)范圍內(nèi)的ansii字符, 還有0xA0 - 0xFF這個(gè)范圍內(nèi)的歐洲字符集, 這里要指出美國(guó)英語(yǔ)只用到0x20-0x7E, 它只考慮了自己的須求, 沒(méi)有考慮其它國(guó)家的須求, 在歐洲是有拉丁字符的, 所以歐洲國(guó)家擴(kuò)展了剩余的0xA0 - 0xFF這個(gè)范圍內(nèi)的來(lái)表示歐洲的字符集, 其實(shí)我們國(guó)家的漢字也是在這個(gè)范圍內(nèi)擴(kuò)展的, 不過(guò)我們用的是二個(gè)字節(jié)來(lái)表示一個(gè)漢字, 是因?yàn)闈h字太多, 這區(qū)區(qū)94個(gè)值無(wú)法滿足漢字的須求, 94*94就差不多了. 漢字用到的第一個(gè)值為0xb HK: Hiragana and Katakana[日文平假名與片假名]. 1HK: ASCII, European extensions, Hiragana and Katakana[ansii,歐洲字符集,日文平假與片假]. D: Digit fonts[數(shù)字及運(yùn)算符號(hào)集]. 以上的ASCII/1/HK/1Hk/D都是字符集的簡(jiǎn)單代號(hào). 3. 回過(guò)頭來(lái)再看你的GUI_Font__21_Prop2,GUI_Font__21_Prop1. 那么很容易理解,GUI_Font__21_Prop2是歐洲字符集, 范圍當(dāng)然是0xa0-0xff. GUI_Font__21_Prop1中存的是ASCII字符集. 至于GUI_Font__21_CharInfo中則存的是全部的字符集的點(diǎn)陣信息, 包含所有字符信息. 最后, 將字體中包含的所有字符集用鏈表連接起來(lái). 再將這個(gè)鏈表頭指針存到字體結(jié)構(gòu)(GUI_FONT)中的存放均衡字體的指針(const GUI_FONT_PROP* pProp)當(dāng)中, 這樣在處理字符的顯示, 可以在這鏈表中查找所要顯示的字符是在哪一個(gè)字符集中, 從而找到它的字符信息(即點(diǎn)陣數(shù)據(jù)及寬高). typedef struct { GUI_DISPCHAR* pfDispChar; GUI_GETCHARDISTX* pfGetCharDistX; GUI_GETFONTINFO* pfGetFontInfo; GUI_ISINFONT* pfIsInFont; tGUI_ENC_APIList* pafEncode; U8 YSize; U8 YDist; U8 XMag; U8 YMag; union {//此聯(lián)合處存放均衡或是待寬字符集信息... void *pFontData; const GUI_FONT_MONO* pMono; const GUI_FONT_PROP* pProp; } p; U8 Baseline; } GUI_FONT; 在GUI_Font__21_Prop1中的(void GUI_FLASH *)&GUI_Font__21_Prop2/* pointer to next GUI_FONT_PROP */ 在GUI_Font__21_Prop2中的(void GUI_FLASH *)&GUI_Font__21_Prop3/* pointer to next GUI_FONT_PROP */ 在GUI_FONT_MONO當(dāng)中的成員next就是指向一下字符集的... 這個(gè)鏈表是人工寫(xiě)成的.....鏈表最后一個(gè)成員的next指向空.... 這個(gè)鏈表的構(gòu)造, 其實(shí)還是為了使用, 所以要理解它, 就要理解是如何用的. 均衡字體的顯示, 是在GUIPROPAA_DispChar這個(gè)函數(shù)中處理的, 要理解鏈表的構(gòu)造就要理解這個(gè)函數(shù),下面做簡(jiǎn)要的分析.... void GUIPROPAA_DispChar(U16P c) { int BytesPerLine; GUI_DRAWMODE DrawMode = GUI_Context.TextMode; const GUI_FONT_PROP* pProp = GUIPROP_FindChar(GUI_Context.pAFont->p.pProp, c); if (pProp) { GUI_DRAWMODE OldDrawMode; const GUI_CHARINFO* pCharInfo = pProp->paCharInfo+(c-pProp->First); BytesPerLine = pCharInfo->BytesPerLine; OldDrawMode = LCD_SetDrawMode(DrawMode); Draw ( GUI_Context.DispPosX, GUI_Context.DispPosY, (pCharInfo->XSize+1)/2, GUI_Context.pAFont->YSize, BytesPerLine, (U8 const*) pCharInfo->pData ); LCD_SetDrawMode(OldDrawMode); /* Restore draw mode */ GUI_Context.DispPosX += (pCharInfo->XDist+1)/2; } } 而理解GUIPROPAA_DispChar的重點(diǎn), 就是要理解它當(dāng)中調(diào)用的用來(lái)尋找要顯示的字符的字符信息的函數(shù)GUIPROP_FindChar, GUIPROP_FindChar主要是尋找字符所在的字符集(其實(shí)這個(gè)字符集在漢字應(yīng)用當(dāng)中,有些不同. 在hzk12.c中, 作者是將漢字接區(qū)來(lái)分集的, 下面我們以hzk12.c中的構(gòu)造來(lái)講解字符集鏈表: hzk12.c 中共分成(0xa hzk12.c中, 字符集鏈表構(gòu)成為: 字符集鏈表第一個(gè)元素為ascii字符集,第二個(gè)為機(jī)內(nèi)碼處于(0xa 了解了漢字庫(kù)的這個(gè)字符集鏈表的構(gòu)成, 那么現(xiàn)在來(lái)看一下如何尋找一個(gè)要顯示的字符處于哪個(gè)字符集當(dāng)中, 找了那個(gè)字符集才能找到這個(gè)字符的字符信息.... static const GUI_FONT_PROP* GUIPROP_FindChar(const GUI_FONT_PROP* pProp, U16P c) { for (pProp = GUI_Context.pAFont->p.pProp; pProp; pProp=(const GUI_FONT_PROP*) pProp->pNext) { if ((c>=pProp->First) && (c<=pProp->Last)) break; } return pProp; } GUIPROP_FindChar 其實(shí)就是查找字符的機(jī)內(nèi)碼是位于哪個(gè)字符集之間, 比如尋找"啊"字, 機(jī)內(nèi)碼為0xb const GUI_CHARINFO* pCharInfo = pProp->paCharInfo+(c-pProp->First);
c-pProp->First即為該字符在此字符集中的偏移, pProp->paCharInfo為該字符集中第一個(gè)字符地址... 這樣就找到了要顯示的字符的字符信息了(寬高及點(diǎn)陣數(shù)等), 理解了這個(gè)過(guò)程, 那么反過(guò)來(lái)理解這個(gè)字符集為何要如此構(gòu)造, 就比較容易了... 比如說(shuō): 為什么要將漢字分成86個(gè)字符集合? 這是由于漢字的機(jī)內(nèi)碼并沒(méi)有用到所有的0xffff--xa 比如說(shuō), 如下所示: GUI_FLASH const GUI_FONT_PROP GUI_FontHZ12_Propa1= { 0xa 0xfefe, &GUI_FontHZ12_CharInfo[ 96], (void *)&GUI_FontHZ12_Propa2 }; 用以下一個(gè)結(jié)點(diǎn)來(lái)表示所有漢字, 如同ACSII, 那么我們分析一下它為什么不可以: 首先對(duì)于區(qū)間(0xa
[ucgui原創(chuàng)]在UCGUI中增加漢字顯示的說(shuō)明. 在UCGUI中增加漢字顯示的說(shuō)明. 作 者: ucgui UCGUI中本身只支持E,沒(méi)有提供中文的字庫(kù)的.C源碼文件, 但是我們可以通過(guò)下面的方式來(lái)實(shí)現(xiàn)漢字的顯示... 我們知道, 在DOS下經(jīng)常利用點(diǎn)陣來(lái)顯示漢字. 帶漢字顯示的程序,很多都會(huì)自己帶上漢字庫(kù), 這個(gè)字庫(kù)里放的就是每個(gè)漢字的點(diǎn)陣. 一. 漢字的顯示原理之一 -----------------點(diǎn)陣漢字. 簡(jiǎn)單的理解, 所謂一個(gè)字的點(diǎn)陣. 其實(shí)就是指這個(gè)漢字用多少個(gè)象素點(diǎn)來(lái)描述. 每個(gè)象素點(diǎn)顯示為什么顏色, 通常情況下, HZK16采用的是16*16點(diǎn)陣, 即256個(gè)象素點(diǎn)描述一個(gè)漢字. 那么,關(guān)于那些點(diǎn)顯示為前景色, 那些點(diǎn)顯示為背景色, 是如何得知的呢?? 可以這樣來(lái)考慮, 你在紙上比較正正方方的寫(xiě)一個(gè)規(guī)則的楷字, 然后在這個(gè)字的從上到下,左到右, 分別畫(huà)十七條直線, 那么這個(gè)字就被放置于一個(gè)16*16的方格之內(nèi), 這樣我們就可以很明顯的看出, 16*16的方格內(nèi)的具體哪些點(diǎn)有筆劃經(jīng)過(guò), 有筆劃經(jīng)過(guò)與沒(méi)筆化經(jīng)過(guò)的即就是應(yīng)該被分別填充上前景色與背景色的點(diǎn). 現(xiàn)在,找到了一個(gè)漢字的點(diǎn)陣, 那么還須要用數(shù)據(jù)來(lái)記錄點(diǎn)陣的信息, 通常情況下, 我們會(huì)用32個(gè)字節(jié)來(lái)表示16*16點(diǎn)陣的漢字, 即每一行用二個(gè)字節(jié)來(lái)記錄十六個(gè)象素點(diǎn)的色色彩情況, 0表示背景色, 1表示前景色. 16行其須要32個(gè)字節(jié). 點(diǎn)陣漢字的原理同時(shí)也決定了它的缺點(diǎn), 他不具務(wù)放大特性, 因?yàn)樗娘@示是基于被定死的點(diǎn)陣, 放大后, 會(huì)產(chǎn)生明顯的鋸齒,非常的難看, 當(dāng)然, 可以進(jìn)行一些光滑處理, 但基本上沒(méi)有多在的改觀. 但點(diǎn)陣漢字簡(jiǎn)易, 對(duì)于復(fù)雜漢字, 它比矢量顯示漢字法更快帶.矢量顯示是基于記錄漢字的筆化的. 對(duì)于簡(jiǎn)單的漢字它比較占優(yōu)勢(shì), 容易放大處理. 但對(duì)于復(fù)雜的漢字, 表示起來(lái), 則筆化太多..復(fù)雜. 二. 關(guān)于字庫(kù)的建立及其原理. 現(xiàn)在講完了漢字點(diǎn)陣. 也說(shuō)了一個(gè)漢字點(diǎn)陣的存放方式, 但具體的點(diǎn)陣如何存放, 讀者也應(yīng)該了解. 通常情況下, 一般的DOS下的程序都會(huì)提供一個(gè)漢字庫(kù), 這樣在脫離漢字平臺(tái)(如UCDO)的支持下也可以進(jìn)行漢字顯示, 但是這樣會(huì)存一個(gè)問(wèn)題, 就是如果每個(gè)DOS下的程序員都這么做的話, 就會(huì)造成一定的磁盤(pán)空間浪費(fèi). 所以有的DOS下的程序,針對(duì)自己所需要的漢字, 就會(huì)定制自己的小型字庫(kù), 那么字庫(kù)的制作到底應(yīng)該如何進(jìn)行呢? 下面我們將就這個(gè)問(wèn)題進(jìn)行一些基本的討論.
實(shí)際上,仔細(xì)觀察ASCII字符表,從第161(即0xa1)個(gè)字符開(kāi)始,后面的字符并不經(jīng)常為E文所使用。充分利用這一特性,將161-255之間的數(shù)值空間作為漢字的標(biāo)識(shí)碼。既然255-161 = 94不能滿足漢字容量的要求,就將每?jī)蓚€(gè)字符并在一塊(即一個(gè)漢字占兩個(gè)字節(jié)),顯然,94* 94 =8836基本上已經(jīng)滿足了常用漢字個(gè)數(shù)的要求。 從以上的討論可以知道, 用二個(gè)字節(jié)來(lái)表示一個(gè)漢字, 其原因就是上面說(shuō)的, 這個(gè)就是我們常說(shuō)的漢字機(jī)內(nèi)碼, 一個(gè)漢字的機(jī)內(nèi)碼是由值都大于0xa1的值組成的. 說(shuō)完機(jī)內(nèi)碼, 有的朋友可能就會(huì)問(wèn)題, 機(jī)內(nèi)碼與建立漢字字庫(kù)有什么關(guān)系呢?? 我們常見(jiàn)的標(biāo)準(zhǔn)的漢字字庫(kù)HZX16(點(diǎn)陣16*16),HZK24(24*24)兩種.由上面的討論我們得知, 一個(gè)漢字點(diǎn)陣須要256個(gè)象素點(diǎn)陣來(lái)表示, 我們采用一個(gè)字節(jié)的8位來(lái)表示八個(gè)象素, 其須32個(gè)字節(jié); 字庫(kù)中要存放的是所有常用的漢字的二進(jìn)制點(diǎn)陣數(shù)據(jù), 它的存放是有序的, 下面我們說(shuō)一下這個(gè)順序: 首先.對(duì)于"我"字來(lái)說(shuō), 它的機(jī)內(nèi)碼是0xce,0xd2; 機(jī)內(nèi)碼每個(gè)字節(jié)均從0xa1開(kāi)始, 那么我們已經(jīng)采用的建立點(diǎn)陣字在庫(kù)中的索引方法是: 將整個(gè)字庫(kù)里面的漢字是94*94的二維數(shù)組, 要找任意一個(gè)漢字的點(diǎn)陣, 就須要知道這個(gè)漢字在這個(gè)二維數(shù)組當(dāng)中的X維與Y維. x維 = (機(jī)內(nèi)碼字節(jié)1-0xa1) & 0x7f; y維 = (機(jī)內(nèi)碼字節(jié)2-0xa1) & 0x7f; 求漢字在X,Y維后, 那么按照每個(gè)漢字占用32個(gè)字節(jié), 則可以得出漢字相對(duì)于字庫(kù)頭的偏移是 offset = (x*94 + y)*32;
其中一級(jí)漢字在16-55..二級(jí)漢字在56-87.是按照一定的規(guī)則來(lái)確定區(qū)位碼的.對(duì)于一級(jí)漢字.是按拼音首字母級(jí)筆劃.二級(jí)漢字是按部首來(lái)的.我特意生了一個(gè)漢字的區(qū)痊碼,機(jī)內(nèi)碼.在字庫(kù)中偏移的文件..大家可以下載來(lái)看一下. 可以知道: 啊-------------區(qū)位碼(x = 15, y = 0); offset=b040; 機(jī)內(nèi)碼:(0xb0,0xa1); 所以漢字的區(qū)內(nèi)碼,機(jī)內(nèi)碼,偏移的信息,請(qǐng)下載這個(gè)文件查看. http://www./home/ucgui/HZK_info.rar 其中,區(qū)位碼(x=0-14)與(88-94)都是沒(méi)有對(duì)應(yīng)漢字的.字庫(kù)中實(shí)際的對(duì)應(yīng)漢字點(diǎn)陣字?jǐn)?shù)為94*72=6768個(gè)漢字. 實(shí)際上, 一個(gè)字庫(kù)中有前16*32個(gè)字節(jié)沒(méi)有表示具體的漢字的, 在字庫(kù)里被用來(lái)表示什么東西沒(méi)有什么具體的要求, 如果說(shuō)你自己要做一個(gè)字庫(kù).那么這一段你可以自己發(fā)揮, 填充為一個(gè)中文的符號(hào),笑臉,特別文字什么的.這些沒(méi)有具體的要求. 同理.對(duì)于(88---94)*32, 你也可以自己發(fā)揮. 然后告知?jiǎng)e人如何使用,因?yàn)檫@個(gè)沒(méi)有標(biāo)準(zhǔn), 所以一定要有特別的說(shuō)明,別人才可可以使用. 在一般的HZK16當(dāng)中, 最前16*32個(gè)節(jié)有表示兩個(gè)大小的"A"及兩個(gè)感嘆號(hào), 一個(gè)在圓內(nèi)的"帥"字..大家可以仔細(xì)看一下,其它幾個(gè)沒(méi)作特別使用.
那么, 在以上我們談了漢字的顯示原理, 漢字字庫(kù)的存放原理, 其實(shí)都是為了更方便的讓我們自由使用.. 在實(shí)際小, 一個(gè)應(yīng)用程序未必須要顯示所有的漢字, 可能他僅須要顯示1000個(gè)常用的漢字, 那么就可制作一個(gè)1000個(gè)常用的小型漢字字庫(kù), 即所需要的漢字庫(kù)從250K降到32K左右了, 大大的減少了資源占用,使用上非常的靈活. 四. 在UCGUI中如何加入漢字顯示的支持. UCGUI中沒(méi)有漢字功能的支持, 但其實(shí)只要稍加改造, 我們就可以解決點(diǎn)陣漢字顯示的問(wèn)題. UCGUI中, 對(duì)于E文的顯示, 也同樣采用的是點(diǎn)陣的方式, 而且有8*8,6*8, 16*8, 16*16等各種點(diǎn)陣, 這里, 我們可以實(shí)現(xiàn)在設(shè)置顯示16*16的E文字體時(shí), 加上我們的漢字顯示, 因?yàn)槭峭瑯拥狞c(diǎn)陣, 我們不用任何改造, 只要有HZK16文件, 就可以在此E文字體下顯示漢字了. 全部的改造基本上集中在這個(gè)函數(shù)內(nèi)部. oid GL_DispLine(const char GUI_FAR *s, int Len, const GUI_RECT *pRect); 這個(gè)函數(shù)在GUI\Core\GUIChar.c 文件內(nèi)部 要支持漢字顯示, 那么必須改成如下形式. void GL_DispLine(const char GUI_FAR *s, int Len, const GUI_RECT *pRect) {
int WriteHZ (int x, int y,const char *p,int color) c1=(p[0]-0xa1)&0x07f; BytesPerLine = 2; //半漢字點(diǎn)陣以二色位圖方式繪出, 前景色/背景色 LCD_SetDrawMode(OldDrawMode); /* Restore draw mode */ |
|
|