日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

GUI漢字顯示原理

 wfsy1983 2011-05-04

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 (0x7F).[僅包含0x20-0x7E這個范圍內(nèi)的ansii字符]

 

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就差不多了. 漢字用到的第一個值為0xb0a1(), 最后一個為0xf7fe(), 在機內(nèi)碼1當中只用到a1+15~a0+86這個范圍的, 關(guān)于機內(nèi)碼是這個意思: 對于""字模,機內(nèi)碼:(0xb0,0xa1), 0xb0""字的機內(nèi)碼1,0xa1為機內(nèi)碼2. 對于機內(nèi)碼2合使用是0xa1~0xff這個范圍內(nèi)的所有值, 關(guān)于機內(nèi)碼及漢字顯示的原理及漢字庫的構(gòu)成, 本論壇中有專門的一篇文章介紹--"ucgui中處理漢字顯示的說明", 請查看此貼, 這里不多說了, 所以范圍是這樣確定的.]

 

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 中共分成(0xa1a1~0xa1fe),(0xa2a1~0xa2fe)...(0xf7a1~0xf7fe)共分成86個字集, 另外加上(0x0020, 0x007f)這個ANSCII字符集, hzk12.c中的鏈表中就其有87個字符集, 這里的字符集的意義就不再是一個標準的字符集了, 而只能稱之為字符的集合而已, 沒有嚴格意義上的字符集的意思).

 

hzk12.c, 字符集鏈表構(gòu)成為: 字符集鏈表第一個元素為ascii字符集,第二個為機內(nèi)碼處于(0xa1a1~0xa1fe)間的漢字集, 最后一個為(0xf7a1,0xf7fe)....

 

了解了漢字庫的這個字符集鏈表的構(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)碼為0xb0a1,那么由上查找, 就可以知道它是位于鏈表中第16(0xb0-0xa1=16)個字符集(機內(nèi)碼處于0xb0a1~0xb0fe)當中, 那么就返回這個字符集的指針. 找到了要顯示的字符所處的字符集, 再根據(jù):

 

    const GUI_CHARINFO* pCharInfo = pProp->paCharInfo+(c-pProp->First);

   

c-pProp->First即為該字符在此字符集中的偏移,  pProp->paCharInfo為該字符集中第一個字符地址... 

 

這樣就找到了要顯示的字符的字符信息了(寬高及點陣數(shù)等), 理解了這個過程, 那么反過來理解這個字符集為何要如此構(gòu)造, 就比較容易了...

 

比如說: 為什么要將漢字分成86個字符集合? 這是由于漢字的機內(nèi)碼并沒有用到所有的0xffff--xa1a1=0x5e5e中連續(xù)的值, 而是間斷的, 0xa1a1~0xa1fe用到了, 0xa200~0xa2a1這段當中的值不能用(因為機內(nèi)碼2小于0xa1), 只能用0xa2a1~0xa2fe, 所以這個特性決定了漢字的機內(nèi)碼分布是顯區(qū)段的, 不能用一個單一的GUI_FONT_PROP結(jié)點來表示出所有的字符集, 因為漢字是區(qū)間分布的, 不是連續(xù)的.

 

比如說, 如下所示:

 

GUI_FLASH  const GUI_FONT_PROP GUI_FontHZ12_Propa1= {

      0xa1a1,

      0xfefe,

      &GUI_FontHZ12_CharInfo[  96],

      (void *)&GUI_FontHZ12_Propa2

};         

用以下一個結(jié)點來表示所有漢字, 如同ACSII, 那么我們分析一下它為什么不可以:

 

首先對于區(qū)間(0xa1a1~0xa1fe)這第一個區(qū)間, 在以上的結(jié)構(gòu)下, 這個區(qū)間內(nèi)的字符還是能夠正確找到所要顯示的字符信息. 但對于(0xa2a1~0xa2fe)這個區(qū)間的,  pProp->paCharInfo+(c-pProp->First)顯然無法找到字符信息. 這是GUI_FontHZ12_CharInfo這個所有字符信息集數(shù)組的結(jié)構(gòu)決定的, 因為漢字未用的區(qū)間的在它上面沒有體現(xiàn), 它上面存放的是將分隔開的漢字區(qū)間連在一起的, 這樣你就無法根據(jù)pProp->paCharInfo+(c-pProp->First)來找到字符的位置了....         

[ucgui原創(chuàng)]在UCGUI中增加漢字顯示的說明.

在UCGUI中增加漢字顯示的說明.

作 者: ucgui
email: ucgui@163.com
home: http://www.
版 本: v1.0.0.1

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字符占一個字節(jié),它的數(shù)值從0到255, 那么漢字字符將如何與ASCII字符區(qū)別開來呢?

實際上,仔細觀察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;


其實,X與Y就是漢字的區(qū)位碼, 漢字的區(qū)位碼是從0-94的. 但實際上只用了16-87..

其中一級漢字在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)用程序中進行漢這顯示的處理

那么, 在以上我們談了漢字的顯示原理, 漢字字庫的存放原理, 其實都是為了更方便的讓我們自由使用..

在實際小, 一個應(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) {
  /*
    Check if we have anything to do at all ...
    If the window manager has already set the clipping rect, it does not
    make sense to due this. So it makes sense only if
    a) The window manager is not used (-> Configuration)
      or
    b) The window manager is inactive (-> Memory device active)
  */
  if (GUI_Context.pClipRect_HL) {
    if (GUI_RectsIntersect(GUI_Context.pClipRect_HL, pRect) == 0)
      return;
  }
  if (GUI_Context.pAFont->pafEncode) {
    GUI_Context.pAFont->pafEncode->pfDispLine(s, Len);
    return;
  }
#if (GUI_SUPPORT_UNICODE)
  {
    U8 c0;
    char UCActive=0;
    while (--Len >=0) {
      c0=*(U8*)s++;
      if (UCActive) {
        if (c0 == GUI_UC_ENDCHAR)
          UCActive = 0;
        else {
          U8  c1 = *(U8*)s++;
          Len--;
          GL_DispChar (GUI_DB2UC(c0, c1));
        }
      } else { /* Unicode not active */
        if (c0 == GUI_UC_STARTCHAR)
          UCActive = 1;
        else
  {
    //增加漢字支持所加的...2005-6-13 0:14:09
    if (c0&0x80 && (*(U8*)s)&0x80){
   char hz[3];
   hz[0]=c0;
   hz[1]=*(U8*)s;
   hz[2]=0;
   WriteHZ(0,0,hz,0);
   s++;
    }
    else
   GL_DispChar(c0);
  }
      }
    }
  }
#else
  {
   U8 c0;
   while (--Len >=0) { 
    c0=*(U8*)s++;
    //增加漢字支持所加的...2005-6-13 0:14:09
    if (c0&0x80 && (*(U8*)s)&0x80){
     char hz[3];
     hz[0]=c0;
     hz[1]=*(U8*)s;
     hz[2]=0;
     WriteHZ(0,0,hz,0);
     s++;
    }
    else{
     GL_DispChar(c0);
    }
   }
  }
#endif
}


處理漢字顯示:

int WriteHZ (int x, int y,const char *p,int color)
{
  U16 c1,c2,rec;
  long l;
  char pixeldata[32];
  int BytesPerLine;
  GUI_DRAWMODE DrawMode = GUI_Context.TextMode;
  GUI_DRAWMODE OldDrawMode;
  if (handle<0 ) return 0;
  if (p==NULL) return 0;

  c1=(p[0]-0xa1)&0x07f;
  c2=(p[1]-0xa1)&0x07f;
  rec=c1*94+c2;  //漢字庫94*94的二維結(jié)構(gòu)...
  l=rec*32L;  //求字庫偏移...
  lseek(handle,l,SEEK_SET);
  read(handle,pixeldata,32);

  BytesPerLine = 2;
  OldDrawMode  = LCD_SetDrawMode(DrawMode);

//半漢字點陣以二色位圖方式繪出, 前景色/背景色
  LCD_DrawBitmap (GUI_Context.DispPosX, GUI_Context.DispPosY,
    HZSIZEX,HZSIZEY,
    1, 1,
    1,            /*Bits per Pixel */
    BytesPerLine,
    (U8*)pixeldata,
//    NULL  /* no palette means default palette */
    &LCD_BKCOLORINDEX  //在csword的bc3.0版本中, 是用NULL, 但在此處要要修改, 表明此位圖所用調(diào)色析             //為二色, 前景色與背景色...
    );

  LCD_SetDrawMode(OldDrawMode); /* Restore draw mode */
  GUI_Context.DispPosX += HZSIZEX;
  return 1;
}

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多