歡迎您光臨本站 登入註冊首頁

在UCGUI中增加漢字顯示

admin @ 2014-03-25 , reply:0

概述

   UCGUI中本身只支持英文,沒有提供中文的字型檔的.C源碼文件,但是我們可以通過下面的方式來實現漢字的顯示...我們知道,在DOS下經常利用點陣來顯示漢字.帶漢字顯……

    UCGUI中本身只支持英文,沒有提供中文的字型檔的.C源碼文件, 但是我們可以通過下面的方式來實現漢字的顯示...我們知道, 在DOS下經常利用點陣來顯示漢字. 帶漢字顯示的程序,很多都會自己帶上漢字型檔, 這個字型檔里放的就是每個漢字的點陣.

一. 漢字的顯示原理之一:點陣漢字
   
簡單的理解, 所謂一個字的點陣. 其實就是指這個漢字用多少個象素點來描述. 每個象素點顯示為什麼顏色, 通常情況下, HZK16採用的是16*16點陣, 即256個象素點描述一個漢字.這些點的顏色分為兩種, 一種是前景色, 一種是顯示為背景色.那麼,關於那些點顯示為前景色, 那些點顯示為背景色, 是如何得知的呢??可以這樣來考慮, 你在紙上比較正正方方的寫一個規則的楷字, 然後在這個字的從上到下,左到右, 分別畫十七條直線, 那麼這個字就被放置於一個16*16的方格之內, 這樣我們就可以很明顯的看出, 16*16的方格內的具體哪些點有筆劃經過, 有筆劃經過與沒筆化經過的即就是應該被分別填充上前景色與背景色的點.現在,找到了一個漢字的點陣, 那麼還須要用數據來記錄點陣的信息, 通常情況下, 我們會用32個位元組來表示16*16點陣的漢字, 即每一行用二個位元組來記錄十六個象素點的色色彩情況, 0表示背景色, 1表示前景色. 16行其須要32個位元組.
    點陣漢字的原理同時也決定了它的缺點, 他不具務放大特性, 因為它的顯示是基於被定死的點陣, 放大后, 會產生明顯的鋸齒,非常的難看, 當然, 可以進行一些光滑處理, 但基本上沒有多在的改觀.但點陣漢字簡易, 對於複雜漢字, 它比矢量顯示漢字法更快帶.矢量顯示是基於記錄漢字的筆化的. 對於簡單的漢字它比較佔優勢, 容易放大處理. 但對於複雜的漢字, 表示起來, 則筆化太多..複雜.

二. 關於字型檔的建立及其原理
   
現在講完了漢字點陣. 也說了一個漢字點陣的存放方式, 但具體的點陣如何存放, 讀者也應該了解.
    通常情況下, 一般的DOS下的程序都會提供一個漢字型檔, 這樣在脫離漢字平台(如UCDO)的支持下也可以進行漢字顯示, 但是這樣會存一個問題, 就是如果每個DOS下的程序員都這麼做的話, 就會造成一定的磁碟空間浪費. 所以有的DOS下的程序,針對自己所需要的漢字, 就會定製自己的小型字型檔, 那麼字型檔的製作到底應該如何進行呢? 下面我們將就這個問題進行一些基本的討論.
    眾所周知,一個ASCII字元佔一個位元組,它的數值從0到255, 那麼漢字字元將如何與ASCII字元區別開來呢?
    實際上,仔細觀察ASCII字元表,從第161(即0xa1)個字元開始,後面的字元並不經常為E文所使用。充分利用這一特性,將161-255之間的數值空間作為漢字的標識碼。既然255-161 = 94不能滿足漢字容量的要求,就將每兩個字元並在一塊(即一個漢字佔兩個位元組),顯然,94* 94 =8836基本上已經滿足了常用漢字個數的要求。
    從以上的討論可以知道, 用二個位元組來表示一個漢字, 其原因就是上面說的, 這個就是我們常說的漢字機內碼, 一個漢字的機內碼是由值都大於0xa1的值組成的.
    說完機內碼, 有的朋友可能就會問題, 機內碼與建立漢字字型檔有什麼關係呢??
    我們常見的標準的漢字字型檔HZX16(點陣16*16),HZK24(24*24)兩種.由上面的討論我們得知, 一個漢字點陣須要256個象素點陣來表示, 我們採用一個位元組的8位來表示八個象素, 其須32個位元組; 字型檔中要存放的是所有常用的漢字的二進位點陣數據, 它的存放是有序的, 下面我們說一下這個順序:
    首先.對於"我"字來說, 它的機內碼是0xce,0xd2; 機內碼每個位元組均從0xa1開始, 那麼我們已經採用的建立點陣字在庫中的索引方法是:
    將整個字型檔裡面的漢字是94*94的二維數組, 要找任意一個漢字的點陣, 就須要知道這個漢字在這個二維數組當中的X維與Y維.
x維 = (機內碼位元組1-0xa1) & 0x7f;
y維 = (機內碼位元組2-0xa1) & 0x7f;
    求漢字在X,Y維后, 那麼按照每個漢字佔用32個位元組, 則可以得出漢字相對於字型檔頭的偏移是 offset = (x*94 + y)*32;
    其實,X與Y就是漢字的區位碼, 漢字的區位碼是從0-94的. 但實際上只用了16-87..
    其中一級漢字在16-55..二級漢字在56-87.是按照一定的規則來確定區位碼的.對於一級漢字.是按拼音首字母級筆劃.二級漢字是按部首來的.我特意生了一個漢字的區痊碼,機內碼.在字型檔中偏移的文件..大家可以下載來看一下. 可以知道:
啊-------------區位碼(x = 15, y = 0); offset=b040; 機內碼:(0xb0,0xa1);
所以漢字的區內碼,機內碼,偏移的信息,請下載這個文件查看.
http://www.macro-tax.com/home/ucgui/HZK_info.rar
    其中,區位碼(x=0-14)與(88-94)都是沒有對應漢字的.字型檔中實際的對應漢字點陣字數為94*72=6768個漢字.
    實際上, 一個字型檔中有前16*32個位元組沒有表示具體的漢字的, 在字型檔里被用來表示什麼東西沒有什麼具體的要求, 如果說你自己要做一個字型檔.那麼這一段你可以自己發揮, 填充為一個中文的符號,笑臉,特別文字什麼的.這些沒有具體的要求.
    同理.對於(88---94)*32, 你也可以自己發揮. 然後告知別人如何使用,因為這個沒有標準, 所以一定要有特別的說明,別人才可可以使用.
    在一般的HZK16當中, 最前16*32個節有表示兩個大小的"A"及兩個感嘆號, 一個在圓內的"帥"字..大家可以仔細看一下,其它幾個沒作特別使用.

三.應用程序中進行漢這顯示的處理
    那麼, 在以上我們談了漢字的顯示原理, 漢字字型檔的存放原理, 其實都是為了更方便的讓我們自由使用..在實際小, 一個應用程序未必須要顯示所有的漢字, 可能他僅須要顯示1000個常用的漢字, 那麼就可製作一個1000個常用的小型漢字字型檔, 即所需要的漢字型檔從250K降到32K左右了, 大大的減少了資源佔用,使用上非常的靈活.

四. 在UCGUI中如何加入漢字顯示的支持
   
UCGUI中沒有漢字功能的支持, 但其實只要稍加改造, 我們就可以解決點陣漢字顯示的問題.UCGUI中, 對於E文的顯示, 也同樣採用的是點陣的方式, 而且有8*8,6*8, 16*8, 16*16等各種點陣, 這裡, 我們可以實現在設置顯示16*16的E文字體時, 加上我們的漢字顯示, 因為是同樣的點陣, 我們不用任何改造, 只要有HZK16文件, 就可以在此E文字體下顯示漢字了.
    全部的改造基本上集中在這個函數內部.
oid GL_DispLine(const char GUI_FAR *s, int Len, const GUI_RECT *pRect);
    這個函數在GUICoreGUIChar.c 文件內部,要支持漢字顯示, 那麼必須改成如下形式.

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
  {
    //增加漢字支持所加的...
    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的二維結構...
  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, 但在此處要要修改, 表明此點陣圖所用調色析             //為二色, 前景色與背景色...
    );

  LCD_SetDrawMode(OldDrawMode); /* Restore draw mode */
  GUI_Context.DispPosX += HZSIZEX;
  return 1;
}
    另外, 除了以上所講的, 我在網上發現如下的一篇文章非常適合大家加強對漢字處理的理解. 漢字處理在DOS時代是一個比較熱門的技術, 但在現在的WIN時代.沒有什麼人關注了, 但是在嵌入式開發了, 它還有一定的用武之地, 理解它還是有一定的幫助的.
    一篇介紹漢字處理的文章, 非常不錯, 很基礎,很明白, 其分四節來講漢字的基本原理.
http://www.vcer.net/showTip.jsp?tipid=2291


[admin via 研發互助社區 ] 在UCGUI中增加漢字顯示已經有3130次圍觀

http://cocdig.com/docs/show-post-42096.html