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